# include <linux/fs.h>
# include <linux/falloc.h>
# include <linux/xattr.h>
-# define FUSE_PLATFORM_OPTS ",nonempty,big_writes"
+# define FUSE_PLATFORM_OPTS ",big_writes"
# ifdef HAVE_SYS_ACL_H
# define TRANSLATE_LINUX_ACLS
# endif
#include "ext2fs/ext2fs.h"
#include "ext2fs/ext2_fs.h"
+#include "../version.h"
+
#ifdef ENABLE_NLS
#include <libintl.h>
#include <locale.h>
errcode_t ext2fs_run_ext3_journal(ext2_filsys *fs);
+#ifdef CONFIG_JBD_DEBUG /* Enabled by configure --enable-jbd-debug */
+int journal_enable_debug = -1;
+#endif
+
/* ACL translation stuff */
#ifdef TRANSLATE_LINUX_ACLS
/*
typedef struct {
u_int32_t a_version;
+#if __GNUC_PREREQ (4, 8)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
acl_ea_entry a_entries[0];
+#if __GNUC_PREREQ (4, 8)
+#pragma GCC diagnostic pop
+#endif
} acl_ea_header;
static inline size_t acl_ea_size(int count)
unsigned long magic;
ext2_filsys fs;
pthread_mutex_t bfl;
+ char *device;
+ int ro;
+ int debug;
+ int no_default_opts;
int panic_on_error;
int minixdf;
+ int fakeroot;
int alloc_all_blocks;
+ int norecovery;
FILE *err_fp;
unsigned int next_generation;
};
static int check_inum_access(ext2_filsys fs, ext2_ino_t ino, mode_t mask)
{
struct fuse_context *ctxt = fuse_get_context();
+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
struct ext2_inode inode;
mode_t perms;
errcode_t err;
dbg_printf("access ino=%d mask=e%s%s%s perms=0%o fuid=%d fgid=%d "
"uid=%d gid=%d\n", ino,
(mask & R_OK ? "r" : ""), (mask & W_OK ? "w" : ""),
- (mask & X_OK ? "x" : ""), perms, inode.i_uid, inode.i_gid,
- ctxt->uid, ctxt->gid);
+ (mask & X_OK ? "x" : ""), perms, inode_uid(inode),
+ inode_gid(inode), ctxt->uid, ctxt->gid);
/* existence check */
if (mask == 0)
return -EACCES;
/* Figure out what root's allowed to do */
- if (ctxt->uid == 0) {
+ if (ff->fakeroot || ctxt->uid == 0) {
/* Non-file access always ok */
if (!LINUX_S_ISREG(inode.i_mode))
return 0;
}
/* allow owner, if perms match */
- if (inode.i_uid == ctxt->uid) {
+ if (inode_uid(inode) == ctxt->uid) {
if ((mask & (perms >> 6)) == mask)
return 0;
return -EACCES;
}
/* allow group, if perms match */
- if (inode.i_gid == ctxt->gid) {
+ if (inode_gid(inode) == ctxt->gid) {
if ((mask & (perms >> 3)) == mask)
return 0;
return -EACCES;
return ff;
}
-static blkcnt_t blocks_from_inode(ext2_filsys fs,
- struct ext2_inode_large *inode)
-{
- blkcnt_t b;
-
- b = inode->i_blocks;
- if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_HUGE_FILE)
- b += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32;
-
- if (!(fs->super->s_feature_ro_compat &
- EXT4_FEATURE_RO_COMPAT_HUGE_FILE) ||
- !(inode->i_flags & EXT4_HUGE_FILE_FL))
- b *= fs->blocksize / 512;
- b *= EXT2FS_CLUSTER_RATIO(fs);
-
- return b;
-}
-
static int stat_inode(ext2_filsys fs, ext2_ino_t ino, struct stat *statbuf)
{
struct ext2_inode_large inode;
statbuf->st_ino = ino;
statbuf->st_mode = inode.i_mode;
statbuf->st_nlink = inode.i_links_count;
- statbuf->st_uid = inode.i_uid;
- statbuf->st_gid = inode.i_gid;
+ statbuf->st_uid = inode_uid(inode);
+ statbuf->st_gid = inode_gid(inode);
statbuf->st_size = EXT2_I_SIZE(&inode);
statbuf->st_blksize = fs->blocksize;
- statbuf->st_blocks = blocks_from_inode(fs, &inode);
+ statbuf->st_blocks = ext2fs_get_stat_i_blocks(fs,
+ (struct ext2_inode *)&inode);
EXT4_INODE_GET_XTIME(i_atime, &tv, &inode);
statbuf->st_atime = tv.tv_sec;
EXT4_INODE_GET_XTIME(i_mtime, &tv, &inode);
len--;
if (inode.i_size < len)
len = inode.i_size;
- if (ext2fs_inode_data_blocks2(fs, &inode) ||
- (inode.i_flags & EXT4_INLINE_DATA_FL)) {
+ if (ext2fs_is_fast_symlink(&inode))
+ memcpy(buf, (char *)inode.i_block, len);
+ else {
/* big/inline symlink */
err = ext2fs_file_open(fs, ino, 0, &file);
ret = translate_error(fs, ino, err);
goto out;
}
- } else
- /* inline symlink */
- memcpy(buf, (char *)inode.i_block, len);
+ }
buf[len] = 0;
if (fs_writeable(fs)) {
struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
ext2_filsys fs;
ext2_ino_t parent, child;
- char *temp_path = strdup(path);
+ char *temp_path;
errcode_t err;
char *node_name, a;
int filetype;
fs = ff->fs;
dbg_printf("%s: path=%s mode=0%o dev=0x%x\n", __func__, path, mode,
(unsigned int)dev);
+ temp_path = strdup(path);
if (!temp_path) {
ret = -ENOMEM;
goto out;
inode.i_links_count = 1;
inode.i_extra_isize = sizeof(struct ext2_inode_large) -
EXT2_GOOD_OLD_INODE_SIZE;
+ inode.i_uid = ctxt->uid;
+ ext2fs_set_i_uid_high(inode, ctxt->uid >> 16);
+ inode.i_gid = ctxt->gid;
+ ext2fs_set_i_gid_high(inode, ctxt->gid >> 16);
err = ext2fs_write_new_inode(fs, child, (struct ext2_inode *)&inode);
if (err) {
struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
ext2_filsys fs;
ext2_ino_t parent, child;
- char *temp_path = strdup(path);
+ char *temp_path;
errcode_t err;
char *node_name, a;
struct ext2_inode_large inode;
FUSE2FS_CHECK_CONTEXT(ff);
fs = ff->fs;
dbg_printf("%s: path=%s mode=0%o\n", __func__, path, mode);
+ temp_path = strdup(path);
if (!temp_path) {
ret = -ENOMEM;
goto out;
}
inode.i_uid = ctxt->uid;
+ ext2fs_set_i_uid_high(inode, ctxt->uid >> 16);
inode.i_gid = ctxt->gid;
+ ext2fs_set_i_gid_high(inode, ctxt->gid >> 16);
inode.i_mode = LINUX_S_IFDIR | (mode & ~(S_ISUID | fs->umask)) |
parent_sgid;
inode.i_generation = ff->next_generation++;
/* Rewrite the directory block checksum, having set i_generation */
if ((inode.i_flags & EXT4_INLINE_DATA_FL) ||
- !EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ !ext2fs_has_feature_metadata_csum(fs->super))
goto out2;
err = ext2fs_new_dir_block(fs, child, parent, &block);
if (err) {
struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
ext2_filsys fs;
ext2_ino_t parent, child;
- char *temp_path = strdup(dest);
+ char *temp_path;
errcode_t err;
char *node_name, a;
struct ext2_inode_large inode;
FUSE2FS_CHECK_CONTEXT(ff);
fs = ff->fs;
dbg_printf("%s: symlink %s to %s\n", __func__, src, dest);
+ temp_path = strdup(dest);
if (!temp_path) {
ret = -ENOMEM;
goto out;
}
inode.i_uid = ctxt->uid;
+ ext2fs_set_i_uid_high(inode, ctxt->uid >> 16);
inode.i_gid = ctxt->gid;
+ ext2fs_set_i_gid_high(inode, ctxt->gid >> 16);
inode.i_generation = ff->next_generation++;
err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode,
struct fuse_context *ctxt = fuse_get_context();
struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
ext2_filsys fs;
- char *temp_path = strdup(dest);
+ char *temp_path;
errcode_t err;
char *node_name, a;
ext2_ino_t parent, ino;
FUSE2FS_CHECK_CONTEXT(ff);
fs = ff->fs;
dbg_printf("%s: src=%s dest=%s\n", __func__, src, dest);
+ temp_path = strdup(dest);
if (!temp_path) {
ret = -ENOMEM;
goto out;
goto out;
}
- if (ctxt->uid != 0 && ctxt->uid != inode.i_uid) {
+ if (!ff->fakeroot && ctxt->uid != 0 && ctxt->uid != inode_uid(inode)) {
ret = -EPERM;
goto out;
}
* of the user's groups, but FUSE only tells us about the primary
* group.
*/
- if (ctxt->uid != 0 && ctxt->gid != inode.i_gid)
+ if (!ff->fakeroot && ctxt->uid != 0 && ctxt->gid != inode_gid(inode))
mode &= ~S_ISGID;
inode.i_mode &= ~0xFFF;
/* FUSE seems to feed us ~0 to mean "don't change" */
if (owner != (uid_t) ~0) {
/* Only root gets to change UID. */
- if (ctxt->uid != 0 &&
- !(inode.i_uid == ctxt->uid && owner == ctxt->uid)) {
+ if (!ff->fakeroot && ctxt->uid != 0 &&
+ !(inode_uid(inode) == ctxt->uid && owner == ctxt->uid)) {
ret = -EPERM;
goto out;
}
inode.i_uid = owner;
+ ext2fs_set_i_uid_high(inode, owner >> 16);
}
if (group != (gid_t) ~0) {
/* Only root or the owner get to change GID. */
- if (ctxt->uid != 0 && inode.i_uid != ctxt->uid) {
+ if (!ff->fakeroot && ctxt->uid != 0 &&
+ inode_uid(inode) != ctxt->uid) {
ret = -EPERM;
goto out;
}
/* XXX: We /should/ check group membership but FUSE */
inode.i_gid = group;
+ ext2fs_set_i_gid_high(inode, group >> 16);
}
ret = update_ctime(fs, ino, &inode);
} else
goto out;
}
- fp->fh = (uint64_t)file;
+ fp->fh = (uintptr_t)file;
out:
if (ret)
{
struct fuse_context *ctxt = fuse_get_context();
struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
- struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh;
+ struct fuse2fs_file_handle *fh =
+ (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
ext2_filsys fs;
ext2_file_t efp;
errcode_t err;
{
struct fuse_context *ctxt = fuse_get_context();
struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
- struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh;
+ struct fuse2fs_file_handle *fh =
+ (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
ext2_filsys fs;
ext2_file_t efp;
errcode_t err;
{
struct fuse_context *ctxt = fuse_get_context();
struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
- struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh;
+ struct fuse2fs_file_handle *fh =
+ (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
ext2_filsys fs;
errcode_t err;
int ret = 0;
{
struct fuse_context *ctxt = fuse_get_context();
struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
- struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh;
+ struct fuse2fs_file_handle *fh =
+ (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
ext2_filsys fs;
errcode_t err;
int ret = 0;
overhead = 0;
else
overhead = fs->desc_blocks +
- fs->group_desc_count *
+ (blk64_t)fs->group_desc_count *
(fs->inode_blocks_per_group + 2);
reserved = ext2fs_r_blocks_count(fs->super);
if (!reserved)
FUSE2FS_CHECK_CONTEXT(ff);
fs = ff->fs;
pthread_mutex_lock(&ff->bfl);
- if (!EXT2_HAS_COMPAT_FEATURE(fs->super,
- EXT2_FEATURE_COMPAT_EXT_ATTR)) {
+ if (!ext2fs_has_feature_xattr(fs->super)) {
ret = -ENOTSUP;
goto out;
}
FUSE2FS_CHECK_CONTEXT(ff);
fs = ff->fs;
pthread_mutex_lock(&ff->bfl);
- if (!EXT2_HAS_COMPAT_FEATURE(fs->super,
- EXT2_FEATURE_COMPAT_EXT_ATTR)) {
+ if (!ext2fs_has_feature_xattr(fs->super)) {
ret = -ENOTSUP;
goto out;
}
ret = check_inum_access(fs, ino, R_OK);
if (ret)
- goto out2;
+ goto out;
err = ext2fs_xattrs_open(fs, ino, &h);
if (err) {
FUSE2FS_CHECK_CONTEXT(ff);
fs = ff->fs;
pthread_mutex_lock(&ff->bfl);
- if (!EXT2_HAS_COMPAT_FEATURE(fs->super,
- EXT2_FEATURE_COMPAT_EXT_ATTR)) {
+ if (!ext2fs_has_feature_xattr(fs->super)) {
ret = -ENOTSUP;
goto out;
}
goto out3;
}
- err = ext2fs_xattrs_write(h);
- if (err) {
- ret = translate_error(fs, ino, err);
- goto out3;
- }
-
ret = update_ctime(fs, ino, NULL);
out3:
if (cvalue != value)
FUSE2FS_CHECK_CONTEXT(ff);
fs = ff->fs;
pthread_mutex_lock(&ff->bfl);
- if (!EXT2_HAS_COMPAT_FEATURE(fs->super,
- EXT2_FEATURE_COMPAT_EXT_ATTR)) {
+ if (!ext2fs_has_feature_xattr(fs->super)) {
ret = -ENOTSUP;
goto out;
}
goto out2;
}
- err = ext2fs_xattrs_write(h);
- if (err) {
- ret = translate_error(fs, ino, err);
- goto out2;
- }
-
ret = update_ctime(fs, ino, NULL);
out2:
err = ext2fs_xattrs_close(&h);
{
struct fuse_context *ctxt = fuse_get_context();
struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
- struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh;
+ struct fuse2fs_file_handle *fh =
+ (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
ext2_filsys fs;
errcode_t err;
struct readdir_iter i;
struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
ext2_filsys fs;
ext2_ino_t parent, child;
- char *temp_path = strdup(path);
+ char *temp_path;
errcode_t err;
char *node_name, a;
int filetype;
FUSE2FS_CHECK_CONTEXT(ff);
fs = ff->fs;
dbg_printf("%s: path=%s mode=0%o\n", __func__, path, mode);
+ temp_path = strdup(path);
if (!temp_path) {
ret = -ENOMEM;
goto out;
inode.i_links_count = 1;
inode.i_extra_isize = sizeof(struct ext2_inode_large) -
EXT2_GOOD_OLD_INODE_SIZE;
- if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) {
+ inode.i_uid = ctxt->uid;
+ ext2fs_set_i_uid_high(inode, ctxt->uid >> 16);
+ inode.i_gid = ctxt->gid;
+ ext2fs_set_i_gid_high(inode, ctxt->gid >> 16);
+ if (ext2fs_has_feature_extents(fs->super)) {
ext2_extent_handle_t handle;
inode.i_flags &= ~EXT4_EXTENTS_FL;
{
struct fuse_context *ctxt = fuse_get_context();
struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
- struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh;
+ struct fuse2fs_file_handle *fh =
+ (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
ext2_filsys fs;
ext2_file_t efp;
errcode_t err;
struct fuse_context *ctxt = fuse_get_context();
struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
ext2_filsys fs;
- struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh;
+ struct fuse2fs_file_handle *fh =
+ (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
int ret = 0;
FUSE2FS_CHECK_CONTEXT(ff);
int ret;
__u32 flags = *(__u32 *)data;
struct fuse_context *ctxt = fuse_get_context();
+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
dbg_printf("%s: ino=%d\n", __func__, fh->ino);
if (err)
return translate_error(fs, fh->ino, err);
- if (ctxt->uid != 0 && inode.i_uid != ctxt->uid)
+ if (!ff->fakeroot && ctxt->uid != 0 && inode_uid(inode) != ctxt->uid)
return -EPERM;
if ((inode.i_flags ^ flags) & ~FUSE2FS_MODIFIABLE_IFLAGS)
int ret;
__u32 generation = *(__u32 *)data;
struct fuse_context *ctxt = fuse_get_context();
+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
dbg_printf("%s: ino=%d\n", __func__, fh->ino);
if (err)
return translate_error(fs, fh->ino, err);
- if (ctxt->uid != 0 && inode.i_uid != ctxt->uid)
+ if (!ff->fakeroot && ctxt->uid != 0 && inode_uid(inode) != ctxt->uid)
return -EPERM;
inode.i_generation = generation;
{
struct fuse_context *ctxt = fuse_get_context();
struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
- struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh;
+ struct fuse2fs_file_handle *fh =
+ (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
ext2_filsys fs;
int ret = 0;
{
struct fuse_context *ctxt = fuse_get_context();
struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
- struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh;
+ struct fuse2fs_file_handle *fh =
+ (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
ext2_filsys fs;
struct ext2_inode_large inode;
blk64_t start, end;
{
struct fuse_context *ctxt = fuse_get_context();
struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
- struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh;
+ struct fuse2fs_file_handle *fh =
+ (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
ext2_filsys fs;
struct ext2_inode_large inode;
blk64_t start, end;
return (size_t) r == sz;
}
-static void print_help(const char *progname)
+enum {
+ FUSE2FS_VERSION,
+ FUSE2FS_HELP,
+ FUSE2FS_HELPFULL,
+};
+
+#define FUSE2FS_OPT(t, p, v) { t, offsetof(struct fuse2fs, p), v }
+
+static struct fuse_opt fuse2fs_opts[] = {
+ FUSE2FS_OPT("ro", ro, 1),
+ FUSE2FS_OPT("errors=panic", panic_on_error, 1),
+ FUSE2FS_OPT("minixdf", minixdf, 1),
+ FUSE2FS_OPT("fakeroot", fakeroot, 1),
+ FUSE2FS_OPT("fuse2fs_debug", debug, 1),
+ FUSE2FS_OPT("no_default_opts", no_default_opts, 1),
+ FUSE2FS_OPT("norecovery", norecovery, 1),
+
+ FUSE_OPT_KEY("-V", FUSE2FS_VERSION),
+ FUSE_OPT_KEY("--version", FUSE2FS_VERSION),
+ FUSE_OPT_KEY("-h", FUSE2FS_HELP),
+ FUSE_OPT_KEY("--help", FUSE2FS_HELP),
+ FUSE_OPT_KEY("--helpfull", FUSE2FS_HELPFULL),
+ FUSE_OPT_END
+};
+
+
+static int fuse2fs_opt_proc(void *data, const char *arg,
+ int key, struct fuse_args *outargs)
{
- printf(_("Usage: %s dev mntpt [-o options] [fuse_args]\n"), progname);
+ struct fuse2fs *ff = data;
+
+ switch (key) {
+ case FUSE_OPT_KEY_NONOPT:
+ if (!ff->device) {
+ ff->device = strdup(arg);
+ return 0;
+ }
+ return 1;
+ case FUSE2FS_HELP:
+ case FUSE2FS_HELPFULL:
+ fprintf(stderr,
+ "usage: %s device/image mountpoint [options]\n"
+ "\n"
+ "general options:\n"
+ " -o opt,[opt...] mount options\n"
+ " -h --help print help\n"
+ " -V --version print version\n"
+ "\n"
+ "fuse2fs options:\n"
+ " -o ro read-only mount\n"
+ " -o errors=panic dump core on error\n"
+ " -o minixdf minix-style df\n"
+ " -o fakeroot pretend to be root for permission checks\n"
+ " -o no_default_opts do not include default fuse options\n"
+ " -o norecovery don't replay the journal (implies ro)\n"
+ " -o fuse2fs_debug enable fuse2fs debugging\n"
+ "\n",
+ outargs->argv[0]);
+ if (key == FUSE2FS_HELPFULL) {
+ fuse_opt_add_arg(outargs, "-ho");
+ fuse_main(outargs->argc, outargs->argv, &fs_ops, NULL);
+ } else {
+ fprintf(stderr, "Try --helpfull to get a list of "
+ "all flags, including the FUSE options.\n");
+ }
+ exit(1);
+
+ case FUSE2FS_VERSION:
+ fprintf(stderr, "fuse2fs %s (%s)\n", E2FSPROGS_VERSION,
+ E2FSPROGS_DATE);
+ fuse_opt_add_arg(outargs, "--version");
+ fuse_main(outargs->argc, outargs->argv, &fs_ops, NULL);
+ exit(0);
+ }
+ return 1;
}
int main(int argc, char *argv[])
{
+ struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+ struct fuse2fs fctx;
errcode_t err;
- char *tok, *arg, *logfile;
- int i;
- int readwrite = 1, panic_on_error = 0, minixdf = 0;
- struct fuse2fs *ff;
+ char *logfile;
char extra_args[BUFSIZ];
- int ret = 0, flags = EXT2_FLAG_64BITS | EXT2_FLAG_EXCLUSIVE;
+ int ret = 0;
+ int flags = EXT2_FLAG_64BITS | EXT2_FLAG_THREADS | EXT2_FLAG_EXCLUSIVE;
- if (argc < 2) {
- print_help(argv[0]);
- return 1;
- }
+ memset(&fctx, 0, sizeof(fctx));
+ fctx.magic = FUSE2FS_MAGIC;
- for (i = 1; i < argc; i++) {
- if (strcmp(argv[i], "--help") == 0) {
- print_help(argv[0]);
- return 1;
- }
+ fuse_opt_parse(&args, &fctx, fuse2fs_opts, fuse2fs_opt_proc);
+ if (fctx.device == NULL) {
+ fprintf(stderr, "Missing ext4 device/image\n");
+ fprintf(stderr, "See '%s -h' for usage\n", argv[0]);
+ exit(1);
}
- for (i = 1; i < argc - 1; i++) {
- if (strcmp(argv[i], "-o"))
- continue;
- arg = argv[i + 1];
- while ((tok = strtok(arg, ","))) {
- arg = NULL;
- if (!strcmp(tok, "ro"))
- readwrite = 0;
- else if (!strcmp(tok, "errors=panic"))
- panic_on_error = 1;
- else if (!strcmp(tok, "minixdf"))
- minixdf = 1;
- }
- }
-
- if (!readwrite)
+ if (fctx.norecovery)
+ fctx.ro = 1;
+ if (fctx.ro)
printf("%s", _("Mounting read-only.\n"));
#ifdef ENABLE_NLS
#endif
add_error_table(&et_ext2_error_table);
- ff = calloc(1, sizeof(*ff));
- if (!ff) {
- perror("init");
- return 1;
- }
- ff->magic = FUSE2FS_MAGIC;
- ff->panic_on_error = panic_on_error;
- ff->minixdf = minixdf;
-
/* Set up error logging */
logfile = getenv("FUSE2FS_LOGFILE");
if (logfile) {
- ff->err_fp = fopen(logfile, "a");
- if (!ff->err_fp) {
+ fctx.err_fp = fopen(logfile, "a");
+ if (!fctx.err_fp) {
perror(logfile);
- goto out_nofs;
+ goto out;
}
} else
- ff->err_fp = stderr;
+ fctx.err_fp = stderr;
/* Will we allow users to allocate every last block? */
if (getenv("FUSE2FS_ALLOC_ALL_BLOCKS")) {
printf(_("%s: Allowing users to allocate all blocks. "
- "This is dangerous!\n"), argv[1]);
- ff->alloc_all_blocks = 1;
+ "This is dangerous!\n"), fctx.device);
+ fctx.alloc_all_blocks = 1;
}
/* Start up the fs (while we still can use stdout) */
ret = 2;
- if (readwrite)
+ if (!fctx.ro)
flags |= EXT2_FLAG_RW;
- err = ext2fs_open2(argv[1], NULL, flags, 0, 0, unix_io_manager,
+ err = ext2fs_open2(fctx.device, NULL, flags, 0, 0, unix_io_manager,
&global_fs);
if (err) {
- printf(_("%s: %s.\n"), argv[1], error_message(err));
- printf(_("Please run e2fsck -fy %s.\n"), argv[1]);
- goto out_nofs;
+ printf(_("%s: %s.\n"), fctx.device, error_message(err));
+ printf(_("Please run e2fsck -fy %s.\n"), fctx.device);
+ goto out;
}
- ff->fs = global_fs;
- global_fs->priv_data = ff;
+ fctx.fs = global_fs;
+ global_fs->priv_data = &fctx;
ret = 3;
- if (EXT2_HAS_INCOMPAT_FEATURE(global_fs->super,
- EXT3_FEATURE_INCOMPAT_RECOVER)) {
- if (readwrite) {
- printf(_("%s: recovering journal\n"), argv[1]);
+
+ if (ext2fs_has_feature_journal_needs_recovery(global_fs->super)) {
+ if (fctx.norecovery) {
+ printf(_("%s: mounting read-only without "
+ "recovering journal\n"),
+ fctx.device);
+ } else if (!fctx.ro) {
+ printf(_("%s: recovering journal\n"), fctx.device);
err = ext2fs_run_ext3_journal(&global_fs);
if (err) {
- printf(_("%s: %s.\n"), argv[1],
+ printf(_("%s: %s.\n"), fctx.device,
error_message(err));
printf(_("Please run e2fsck -fy %s.\n"),
- argv[1]);
+ fctx.device);
goto out;
}
- global_fs->super->s_feature_incompat &=
- ~EXT3_FEATURE_INCOMPAT_RECOVER;
+ ext2fs_clear_feature_journal_needs_recovery(global_fs->super);
ext2fs_mark_super_dirty(global_fs);
} else {
printf("%s", _("Journal needs recovery; running "
}
}
- if (readwrite) {
- if (EXT2_HAS_COMPAT_FEATURE(global_fs->super,
- EXT3_FEATURE_COMPAT_HAS_JOURNAL))
+ if (!fctx.ro) {
+ if (ext2fs_has_feature_journal(global_fs->super))
printf(_("%s: Writing to the journal is not supported.\n"),
- argv[1]);
+ fctx.device);
err = ext2fs_read_inode_bitmap(global_fs);
if (err) {
translate_error(global_fs, 0, err);
printf("%s", _("Warning: Maximal mount count reached, running "
"e2fsck is recommended.\n"));
if (global_fs->super->s_checkinterval > 0 &&
- global_fs->super->s_lastcheck +
- global_fs->super->s_checkinterval <= time(0))
+ (time_t) (global_fs->super->s_lastcheck +
+ global_fs->super->s_checkinterval) <= time(0))
printf("%s", _("Warning: Check time reached; running e2fsck "
"is recommended.\n"));
if (global_fs->super->s_last_orphan)
}
/* Initialize generation counter */
- get_random_bytes(&ff->next_generation, sizeof(unsigned int));
+ get_random_bytes(&fctx.next_generation, sizeof(unsigned int));
- /* Stuff in some fuse parameters of our own */
+ /* Set up default fuse parameters */
snprintf(extra_args, BUFSIZ, "-okernel_cache,subtype=ext4,use_ino,"
- "fsname=%s,attr_timeout=0,allow_other" FUSE_PLATFORM_OPTS,
- argv[1]);
- argv[0] = argv[1];
- argv[1] = argv[2];
- argv[2] = extra_args;
+ "fsname=%s,attr_timeout=0" FUSE_PLATFORM_OPTS,
+ fctx.device);
+ if (fctx.no_default_opts == 0)
+ fuse_opt_add_arg(&args, extra_args);
+
+ if (fctx.fakeroot) {
+#ifdef HAVE_MOUNT_NODEV
+ fuse_opt_add_arg(&args,"-onodev");
+#endif
+#ifdef HAVE_MOUNT_NOSUID
+ fuse_opt_add_arg(&args,"-onosuid");
+#endif
+ }
+
+ if (fctx.debug) {
+ int i;
+
+ printf("fuse arguments:");
+ for (i = 0; i < args.argc; i++)
+ printf(" '%s'", args.argv[i]);
+ printf("\n");
+ }
- pthread_mutex_init(&ff->bfl, NULL);
- fuse_main(argc, argv, &fs_ops, ff);
- pthread_mutex_destroy(&ff->bfl);
+ pthread_mutex_init(&fctx.bfl, NULL);
+ fuse_main(args.argc, args.argv, &fs_ops, &fctx);
+ pthread_mutex_destroy(&fctx.bfl);
ret = 0;
out:
- err = ext2fs_close(global_fs);
- if (err)
- com_err(argv[0], err, "while closing fs");
- global_fs = NULL;
-out_nofs:
- free(ff);
-
+ if (global_fs) {
+ err = ext2fs_close(global_fs);
+ if (err)
+ com_err(argv[0], err, "while closing fs");
+ global_fs = NULL;
+ }
return ret;
}
break;
case EXT2_ET_DIR_NO_SPACE:
is_err = 1;
+ /* fallthrough */
case EXT2_ET_TOOSMALL:
case EXT2_ET_BLOCK_ALLOC_FAIL:
case EXT2_ET_INODE_ALLOC_FAIL:
if (ino)
fprintf(ff->err_fp, "FUSE2FS (%s): %s (inode #%d) at %s:%d.\n",
- fs && fs->device_name ? fs->device_name : "???",
+ fs->device_name ? fs->device_name : "???",
error_message(err), ino, file, line);
else
fprintf(ff->err_fp, "FUSE2FS (%s): %s at %s:%d.\n",
- fs && fs->device_name ? fs->device_name : "???",
+ fs->device_name ? fs->device_name : "???",
error_message(err), file, line);
fflush(ff->err_fp);