Whamcloud - gitweb
Prevent i_dtime from being mistaken for an inode number post-2038 wraparound
[tools/e2fsprogs.git] / misc / fuse2fs.c
index 94cd5f6..5927fdf 100644 (file)
@@ -9,7 +9,6 @@
  * %End-Header%
  */
 #define _FILE_OFFSET_BITS 64
-#define FUSE_USE_VERSION 29
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE
 #endif
 # include <linux/fs.h>
 # include <linux/falloc.h>
 # include <linux/xattr.h>
-# define FUSE_PLATFORM_OPTS    ",big_writes"
 # ifdef HAVE_SYS_ACL_H
 #  define TRANSLATE_LINUX_ACLS
 # endif
-#else
-# define FUSE_PLATFORM_OPTS    ""
 #endif
 #ifdef TRANSLATE_LINUX_ACLS
 # include <sys/acl.h>
 #include <inttypes.h>
 #include "ext2fs/ext2fs.h"
 #include "ext2fs/ext2_fs.h"
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+# define FUSE_PLATFORM_OPTS    ""
+#else
+# ifdef __linux__
+#  define FUSE_PLATFORM_OPTS   ",use_ino,big_writes"
+# else
+#  define FUSE_PLATFORM_OPTS   ",use_ino"
+# endif
+#endif
 
 #include "../version.h"
 
@@ -324,6 +329,8 @@ struct fuse2fs {
        int minixdf;
        int fakeroot;
        int alloc_all_blocks;
+       int norecovery;
+       unsigned long offset;
        FILE *err_fp;
        unsigned int next_generation;
 };
@@ -726,7 +733,11 @@ static void op_destroy(void *p EXT2FS_ATTR((unused)))
        }
 }
 
-static void *op_init(struct fuse_conn_info *conn)
+static void *op_init(struct fuse_conn_info *conn
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+                       , struct fuse_config *cfg EXT2FS_ATTR((unused))
+#endif
+                       )
 {
        struct fuse_context *ctxt = fuse_get_context();
        struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
@@ -744,7 +755,7 @@ static void *op_init(struct fuse_conn_info *conn)
 #endif
        if (fs->flags & EXT2_FLAG_RW) {
                fs->super->s_mnt_count++;
-               fs->super->s_mtime = time(NULL);
+               ext2fs_set_tstamp(fs->super, s_mtime, time(NULL));
                fs->super->s_state &= ~EXT2_VALID_FS;
                ext2fs_mark_super_dirty(fs);
                err = ext2fs_flush2(fs, 0);
@@ -754,23 +765,6 @@ static void *op_init(struct fuse_conn_info *conn)
        return ff;
 }
 
-static blkcnt_t blocks_from_inode(ext2_filsys fs,
-                                 struct ext2_inode_large *inode)
-{
-       blkcnt_t b;
-
-       b = inode->i_blocks;
-       if (ext2fs_has_feature_huge_file(fs->super))
-               b += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32;
-
-       if (!ext2fs_has_feature_huge_file(fs->super) ||
-           !(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;
@@ -794,7 +788,8 @@ static int stat_inode(ext2_filsys fs, ext2_ino_t ino, struct stat *statbuf)
        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);
@@ -812,7 +807,11 @@ static int stat_inode(ext2_filsys fs, ext2_ino_t ino, struct stat *statbuf)
        return ret;
 }
 
-static int op_getattr(const char *path, struct stat *statbuf)
+static int op_getattr(const char *path, struct stat *statbuf
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+                       , struct fuse_file_info *fi EXT2FS_ATTR((unused))
+#endif
+                       )
 {
        struct fuse_context *ctxt = fuse_get_context();
        struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
@@ -1143,7 +1142,7 @@ static int op_mkdir(const char *path, mode_t mode)
        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)) |
+       inode.i_mode = LINUX_S_IFDIR | (mode & ~S_ISUID) |
                       parent_sgid;
        inode.i_generation = ff->next_generation++;
 
@@ -1244,7 +1243,7 @@ static int remove_inode(struct fuse2fs *ff, ext2_ino_t ino)
                return 0; /* XXX: already done? */
        case 1:
                inode.i_links_count--;
-               inode.i_dtime = fs->now ? fs->now : time(0);
+               ext2fs_set_dtime(fs, EXT2_INODE(&inode));
                break;
        default:
                inode.i_links_count--;
@@ -1556,7 +1555,11 @@ static int update_dotdot_helper(ext2_ino_t dir EXT2FS_ATTR((unused)),
        return 0;
 }
 
-static int op_rename(const char *from, const char *to)
+static int op_rename(const char *from, const char *to
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+                       , unsigned int flags EXT2FS_ATTR((unused))
+#endif
+                       )
 {
        struct fuse_context *ctxt = fuse_get_context();
        struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
@@ -1885,7 +1888,11 @@ out:
        return ret;
 }
 
-static int op_chmod(const char *path, mode_t mode)
+static int op_chmod(const char *path, mode_t mode
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+                       , struct fuse_file_info *fi EXT2FS_ATTR((unused))
+#endif
+                       )
 {
        struct fuse_context *ctxt = fuse_get_context();
        struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
@@ -1944,7 +1951,11 @@ out:
        return ret;
 }
 
-static int op_chown(const char *path, uid_t owner, gid_t group)
+static int op_chown(const char *path, uid_t owner, gid_t group
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+                       , struct fuse_file_info *fi EXT2FS_ATTR((unused))
+#endif
+                       )
 {
        struct fuse_context *ctxt = fuse_get_context();
        struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
@@ -2014,7 +2025,11 @@ out:
        return ret;
 }
 
-static int op_truncate(const char *path, off_t len)
+static int op_truncate(const char *path, off_t len
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+                       , struct fuse_file_info *fi EXT2FS_ATTR((unused))
+#endif
+                       )
 {
        struct fuse_context *ctxt = fuse_get_context();
        struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
@@ -2373,7 +2388,7 @@ static int op_statfs(const char *path EXT2FS_ATTR((unused)),
                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)
@@ -2523,9 +2538,10 @@ static int copy_names(char *name, char *value EXT2FS_ATTR((unused)),
                      size_t value_len EXT2FS_ATTR((unused)), void *data)
 {
        char **b = data;
+       size_t name_len = strlen(name);
 
-       strncpy(*b, name, strlen(name));
-       *b = *b + strlen(name) + 1;
+       memcpy(*b, name, name_len + 1);
+       *b = *b + name_len + 1;
 
        return 0;
 }
@@ -2766,7 +2782,11 @@ static int op_readdir_iter(ext2_ino_t dir EXT2FS_ATTR((unused)),
 
        memcpy(namebuf, dirent->name, dirent->name_len & 0xFF);
        namebuf[dirent->name_len & 0xFF] = 0;
-       ret = i->func(i->buf, namebuf, NULL, 0);
+       ret = i->func(i->buf, namebuf, NULL, 0
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+                       , 0
+#endif
+                       );
        if (ret)
                return DIRENT_ABORT;
 
@@ -2776,7 +2796,11 @@ static int op_readdir_iter(ext2_ino_t dir EXT2FS_ATTR((unused)),
 static int op_readdir(const char *path EXT2FS_ATTR((unused)),
                      void *buf, fuse_fill_dir_t fill_func,
                      off_t offset EXT2FS_ATTR((unused)),
-                     struct fuse_file_info *fp)
+                     struct fuse_file_info *fp
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+                       , enum fuse_readdir_flags flags EXT2FS_ATTR((unused))
+#endif
+                       )
 {
        struct fuse_context *ctxt = fuse_get_context();
        struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
@@ -2964,6 +2988,7 @@ out:
        return ret;
 }
 
+#if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
 static int op_ftruncate(const char *path EXT2FS_ATTR((unused)),
                        off_t len, struct fuse_file_info *fp)
 {
@@ -3037,8 +3062,13 @@ static int op_fgetattr(const char *path EXT2FS_ATTR((unused)),
 
        return ret;
 }
+#endif /* FUSE_VERSION < FUSE_MAKE_VERSION(3, 0) */
 
-static int op_utimens(const char *path, const struct timespec ctv[2])
+static int op_utimens(const char *path, const struct timespec ctv[2]
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+                       , struct fuse_file_info *fi EXT2FS_ATTR((unused))
+#endif
+                       )
 {
        struct fuse_context *ctxt = fuse_get_context();
        struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
@@ -3272,7 +3302,12 @@ static int ioctl_fitrim(ext2_filsys fs, struct fuse2fs_file_handle *fh,
 #endif /* FITRIM */
 
 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
-static int op_ioctl(const char *path EXT2FS_ATTR((unused)), int cmd,
+static int op_ioctl(const char *path EXT2FS_ATTR((unused)),
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+                   unsigned int cmd,
+#else
+                   int cmd,
+#endif
                    void *arg EXT2FS_ATTR((unused)),
                    struct fuse_file_info *fp,
                    unsigned int flags EXT2FS_ATTR((unused)), void *data)
@@ -3616,10 +3651,12 @@ static struct fuse_operations fs_ops = {
        .fsyncdir = op_fsync,
        .access = op_access,
        .create = op_create,
+#if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
        .ftruncate = op_ftruncate,
        .fgetattr = op_fgetattr,
+#endif
        .utimens = op_utimens,
-#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
+#if (FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)) && (FUSE_VERSION < FUSE_MAKE_VERSION(3, 0))
 # if defined(UTIME_NOW) || defined(UTIME_OMIT)
        .flag_utime_omit_ok = 1,
 # endif
@@ -3631,10 +3668,14 @@ static struct fuse_operations fs_ops = {
 #endif
 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
        .ioctl = op_ioctl,
+#if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
        .flag_nullpath_ok = 1,
 #endif
+#endif
 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
+#if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
        .flag_nopath = 1,
+#endif
 # ifdef SUPPORT_FALLOCATE
        .fallocate = op_fallocate,
 # endif
@@ -3673,6 +3714,8 @@ static struct fuse_opt fuse2fs_opts[] = {
        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),
+       FUSE2FS_OPT("offset=%lu",       offset,         0),
 
        FUSE_OPT_KEY("-V",             FUSE2FS_VERSION),
        FUSE_OPT_KEY("--version",      FUSE2FS_VERSION),
@@ -3711,6 +3754,8 @@ static int fuse2fs_opt_proc(void *data, const char *arg,
        "    -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 offset=<bytes>      similar to mount -o offset=<bytes>, mount the partition starting at <bytes>\n"
+       "    -o norecovery          don't replay the journal (implies ro)\n"
        "    -o fuse2fs_debug       enable fuse2fs debugging\n"
        "\n",
                        outargs->argv[0]);
@@ -3740,7 +3785,8 @@ int main(int argc, char *argv[])
        errcode_t err;
        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;
 
        memset(&fctx, 0, sizeof(fctx));
        fctx.magic = FUSE2FS_MAGIC;
@@ -3752,6 +3798,8 @@ int main(int argc, char *argv[])
                exit(1);
        }
 
+       if (fctx.norecovery)
+               fctx.ro = 1;
        if (fctx.ro)
                printf("%s", _("Mounting read-only.\n"));
 
@@ -3786,7 +3834,9 @@ int main(int argc, char *argv[])
        ret = 2;
        if (!fctx.ro)
                flags |= EXT2_FLAG_RW;
-       err = ext2fs_open2(fctx.device, NULL, flags, 0, 0, unix_io_manager,
+       char options[50];
+       sprintf(options, "offset=%lu", fctx.offset);
+       err = ext2fs_open2(fctx.device, options, flags, 0, 0, unix_io_manager,
                           &global_fs);
        if (err) {
                printf(_("%s: %s.\n"), fctx.device, error_message(err));
@@ -3799,7 +3849,11 @@ int main(int argc, char *argv[])
        ret = 3;
 
        if (ext2fs_has_feature_journal_needs_recovery(global_fs->super)) {
-               if (!fctx.ro) {
+               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) {
@@ -3860,7 +3914,7 @@ int main(int argc, char *argv[])
        get_random_bytes(&fctx.next_generation, sizeof(unsigned int));
 
        /* Set up default fuse parameters */
-       snprintf(extra_args, BUFSIZ, "-okernel_cache,subtype=ext4,use_ino,"
+       snprintf(extra_args, BUFSIZ, "-okernel_cache,subtype=ext4,"
                 "fsname=%s,attr_timeout=0" FUSE_PLATFORM_OPTS,
                 fctx.device);
        if (fctx.no_default_opts == 0)
@@ -3984,14 +4038,14 @@ no_translation:
 
        /* Make a note in the error log */
        get_now(&now);
-       fs->super->s_last_error_time = now.tv_sec;
+       ext2fs_set_tstamp(fs->super, s_last_error_time, now.tv_sec);
        fs->super->s_last_error_ino = ino;
        fs->super->s_last_error_line = line;
        fs->super->s_last_error_block = err; /* Yeah... */
        strncpy((char *)fs->super->s_last_error_func, file,
                sizeof(fs->super->s_last_error_func));
-       if (fs->super->s_first_error_time == 0) {
-               fs->super->s_first_error_time = now.tv_sec;
+       if (ext2fs_get_tstamp(fs->super, s_first_error_time) == 0) {
+               ext2fs_set_tstamp(fs->super, s_first_error_time, now.tv_sec);
                fs->super->s_first_error_ino = ino;
                fs->super->s_first_error_line = line;
                fs->super->s_first_error_block = err;