2 * fuse2fs.c - FUSE server for e2fsprogs.
4 * Copyright (C) 2014 Oracle.
7 * This file may be redistributed under the terms of the GNU Public
11 #define _FILE_OFFSET_BITS 64
12 #define FUSE_USE_VERSION 29
19 # include <linux/fs.h>
20 # include <linux/falloc.h>
21 # include <linux/xattr.h>
22 # define FUSE_PLATFORM_OPTS ",nonempty,big_writes"
23 # ifdef HAVE_SYS_ACL_H
24 # define TRANSLATE_LINUX_ACLS
27 # define FUSE_PLATFORM_OPTS ""
29 #ifdef TRANSLATE_LINUX_ACLS
32 #include <sys/ioctl.h>
36 #include "ext2fs/ext2fs.h"
37 #include "ext2fs/ext2_fs.h"
39 #include "../version.h"
44 #define _(a) (gettext(a))
46 #define N_(a) gettext_noop(a)
50 #define P_(singular, plural, n) (ngettext(singular, plural, n))
52 #define NLS_CAT_NAME "e2fsprogs"
55 #define LOCALEDIR "/usr/share/locale"
60 #define P_(singular, plural, n) ((n) == 1 ? (singular) : (plural))
63 static ext2_filsys global_fs; /* Try not to use this directly */
68 # define dbg_printf(f, a...) do {printf("FUSE2FS-" f, ## a); \
72 # define dbg_printf(f, a...)
75 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
78 # define SUPPORT_I_FLAGS
83 #ifdef FALLOC_FL_KEEP_SIZE
84 # define FL_KEEP_SIZE_FLAG FALLOC_FL_KEEP_SIZE
85 # define SUPPORT_FALLOCATE
87 # define FL_KEEP_SIZE_FLAG (0)
90 #ifdef FALLOC_FL_PUNCH_HOLE
91 # define FL_PUNCH_HOLE_FLAG FALLOC_FL_PUNCH_HOLE
93 # define FL_PUNCH_HOLE_FLAG (0)
96 errcode_t ext2fs_run_ext3_journal(ext2_filsys *fs);
98 #ifdef CONFIG_JBD_DEBUG /* Enabled by configure --enable-jbd-debug */
99 int journal_enable_debug = -1;
102 /* ACL translation stuff */
103 #ifdef TRANSLATE_LINUX_ACLS
105 * Copied from acl_ea.h in libacl source; ACLs have to be sent to and from fuse
106 * in this format... at least on Linux.
108 #define ACL_EA_ACCESS "system.posix_acl_access"
109 #define ACL_EA_DEFAULT "system.posix_acl_default"
111 #define ACL_EA_VERSION 0x0002
121 #pragma GCC diagnostic push
122 #pragma GCC diagnostic ignored "-Wpedantic"
123 acl_ea_entry a_entries[0];
124 #pragma GCC diagnostic pop
127 static inline size_t acl_ea_size(int count)
129 return sizeof(acl_ea_header) + count * sizeof(acl_ea_entry);
132 static inline int acl_ea_count(size_t size)
134 if (size < sizeof(acl_ea_header))
136 size -= sizeof(acl_ea_header);
137 if (size % sizeof(acl_ea_entry))
139 return size / sizeof(acl_ea_entry);
143 * ext4 ACL structures, copied from fs/ext4/acl.h.
145 #define EXT4_ACL_VERSION 0x0001
156 } ext4_acl_entry_short;
162 static inline size_t ext4_acl_size(int count)
165 return sizeof(ext4_acl_header) +
166 count * sizeof(ext4_acl_entry_short);
168 return sizeof(ext4_acl_header) +
169 4 * sizeof(ext4_acl_entry_short) +
170 (count - 4) * sizeof(ext4_acl_entry);
174 static inline int ext4_acl_count(size_t size)
178 size -= sizeof(ext4_acl_header);
179 s = size - 4 * sizeof(ext4_acl_entry_short);
181 if (size % sizeof(ext4_acl_entry_short))
183 return size / sizeof(ext4_acl_entry_short);
185 if (s % sizeof(ext4_acl_entry))
187 return s / sizeof(ext4_acl_entry) + 4;
190 static errcode_t fuse_to_ext4_acl(acl_ea_header *facl, size_t facl_sz,
191 ext4_acl_header **eacl, size_t *eacl_sz)
201 facl_count = acl_ea_count(facl_sz);
202 h_sz = ext4_acl_size(facl_count);
203 if (facl_count < 0 || facl->a_version != ACL_EA_VERSION)
204 return EXT2_ET_INVALID_ARGUMENT;
206 err = ext2fs_get_mem(h_sz, &h);
210 h->a_version = ext2fs_cpu_to_le32(EXT4_ACL_VERSION);
211 hptr = (unsigned char *) (h + 1);
212 for (i = 0, a = facl->a_entries; i < facl_count; i++, a++) {
213 e = (ext4_acl_entry *) hptr;
214 e->e_tag = ext2fs_cpu_to_le16(a->e_tag);
215 e->e_perm = ext2fs_cpu_to_le16(a->e_perm);
220 e->e_id = ext2fs_cpu_to_le32(a->e_id);
221 hptr += sizeof(ext4_acl_entry);
227 hptr += sizeof(ext4_acl_entry_short);
230 err = EXT2_ET_INVALID_ARGUMENT;
243 static errcode_t ext4_to_fuse_acl(acl_ea_header **facl, size_t *facl_sz,
244 ext4_acl_header *eacl, size_t eacl_sz)
254 eacl_count = ext4_acl_count(eacl_sz);
255 f_sz = acl_ea_size(eacl_count);
256 if (eacl_count < 0 ||
257 eacl->a_version != ext2fs_cpu_to_le32(EXT4_ACL_VERSION))
258 return EXT2_ET_INVALID_ARGUMENT;
260 err = ext2fs_get_mem(f_sz, &f);
264 f->a_version = ACL_EA_VERSION;
265 hptr = (unsigned char *) (eacl + 1);
266 for (i = 0, a = f->a_entries; i < eacl_count; i++, a++) {
267 e = (ext4_acl_entry *) hptr;
268 a->e_tag = ext2fs_le16_to_cpu(e->e_tag);
269 a->e_perm = ext2fs_le16_to_cpu(e->e_perm);
274 a->e_id = ext2fs_le32_to_cpu(e->e_id);
275 hptr += sizeof(ext4_acl_entry);
281 hptr += sizeof(ext4_acl_entry_short);
284 err = EXT2_ET_INVALID_ARGUMENT;
296 #endif /* TRANSLATE_LINUX_ACLS */
299 * ext2_file_t contains a struct inode, so we can't leave files open.
300 * Use this as a proxy instead.
302 #define FUSE2FS_FILE_MAGIC (0xEF53DEAFUL)
303 struct fuse2fs_file_handle {
309 /* Main program context */
310 #define FUSE2FS_MAGIC (0xEF53DEADUL)
321 int alloc_all_blocks;
323 unsigned int next_generation;
326 #define FUSE2FS_CHECK_MAGIC(fs, ptr, num) do {if ((ptr)->magic != (num)) \
327 return translate_error((fs), 0, EXT2_ET_MAGIC_EXT2_FILE); \
330 #define FUSE2FS_CHECK_CONTEXT(ptr) do {if ((ptr)->magic != FUSE2FS_MAGIC) \
331 return translate_error(global_fs, 0, EXT2_ET_BAD_MAGIC); \
334 static int __translate_error(ext2_filsys fs, errcode_t err, ext2_ino_t ino,
335 const char *file, int line);
336 #define translate_error(fs, ino, err) __translate_error((fs), (err), (ino), \
348 #define EXT4_EPOCH_BITS 2
349 #define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1)
350 #define EXT4_NSEC_MASK (~0UL << EXT4_EPOCH_BITS)
353 * Extended fields will fit into an inode if the filesystem was formatted
354 * with large inodes (-I 256 or larger) and there are not currently any EAs
355 * consuming all of the available space. For new inodes we always reserve
356 * enough space for the kernel's known extended fields, but for inodes
357 * created with an old kernel this might not have been the case. None of
358 * the extended inode fields is critical for correct filesystem operation.
359 * This macro checks if a certain field fits in the inode. Note that
360 * inode-size = GOOD_OLD_INODE_SIZE + i_extra_isize
362 #define EXT4_FITS_IN_INODE(ext4_inode, field) \
363 ((offsetof(typeof(*ext4_inode), field) + \
364 sizeof((ext4_inode)->field)) \
365 <= ((size_t) EXT2_GOOD_OLD_INODE_SIZE + \
366 (ext4_inode)->i_extra_isize)) \
368 static inline __u32 ext4_encode_extra_time(const struct timespec *time)
370 __u32 extra = sizeof(time->tv_sec) > 4 ?
371 ((time->tv_sec - (__s32)time->tv_sec) >> 32) &
373 return extra | (time->tv_nsec << EXT4_EPOCH_BITS);
376 static inline void ext4_decode_extra_time(struct timespec *time, __u32 extra)
378 if (sizeof(time->tv_sec) > 4 && (extra & EXT4_EPOCH_MASK)) {
379 __u64 extra_bits = extra & EXT4_EPOCH_MASK;
381 * Prior to kernel 3.14?, we had a broken decode function,
382 * wherein we effectively did this:
383 * if (extra_bits == 3)
386 time->tv_sec += extra_bits << 32;
388 time->tv_nsec = ((extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
391 #define EXT4_INODE_SET_XTIME(xtime, timespec, raw_inode) \
393 (raw_inode)->xtime = (timespec)->tv_sec; \
394 if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \
395 (raw_inode)->xtime ## _extra = \
396 ext4_encode_extra_time(timespec); \
399 #define EXT4_EINODE_SET_XTIME(xtime, timespec, raw_inode) \
401 if (EXT4_FITS_IN_INODE(raw_inode, xtime)) \
402 (raw_inode)->xtime = (timespec)->tv_sec; \
403 if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \
404 (raw_inode)->xtime ## _extra = \
405 ext4_encode_extra_time(timespec); \
408 #define EXT4_INODE_GET_XTIME(xtime, timespec, raw_inode) \
410 (timespec)->tv_sec = (signed)((raw_inode)->xtime); \
411 if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \
412 ext4_decode_extra_time((timespec), \
413 (raw_inode)->xtime ## _extra); \
415 (timespec)->tv_nsec = 0; \
418 #define EXT4_EINODE_GET_XTIME(xtime, timespec, raw_inode) \
420 if (EXT4_FITS_IN_INODE(raw_inode, xtime)) \
421 (timespec)->tv_sec = \
422 (signed)((raw_inode)->xtime); \
423 if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \
424 ext4_decode_extra_time((timespec), \
425 raw_inode->xtime ## _extra); \
427 (timespec)->tv_nsec = 0; \
430 static void get_now(struct timespec *now)
432 #ifdef CLOCK_REALTIME
433 if (!clock_gettime(CLOCK_REALTIME, now))
437 now->tv_sec = time(NULL);
441 static void increment_version(struct ext2_inode_large *inode)
445 ver = inode->osd1.linux1.l_i_version;
446 if (EXT4_FITS_IN_INODE(inode, i_version_hi))
447 ver |= (__u64)inode->i_version_hi << 32;
449 inode->osd1.linux1.l_i_version = ver;
450 if (EXT4_FITS_IN_INODE(inode, i_version_hi))
451 inode->i_version_hi = ver >> 32;
454 static void init_times(struct ext2_inode_large *inode)
459 EXT4_INODE_SET_XTIME(i_atime, &now, inode);
460 EXT4_INODE_SET_XTIME(i_ctime, &now, inode);
461 EXT4_INODE_SET_XTIME(i_mtime, &now, inode);
462 EXT4_EINODE_SET_XTIME(i_crtime, &now, inode);
463 increment_version(inode);
466 static int update_ctime(ext2_filsys fs, ext2_ino_t ino,
467 struct ext2_inode_large *pinode)
471 struct ext2_inode_large inode;
475 /* If user already has a inode buffer, just update that */
477 increment_version(pinode);
478 EXT4_INODE_SET_XTIME(i_ctime, &now, pinode);
482 /* Otherwise we have to read-modify-write the inode */
483 memset(&inode, 0, sizeof(inode));
484 err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
487 return translate_error(fs, ino, err);
489 increment_version(&inode);
490 EXT4_INODE_SET_XTIME(i_ctime, &now, &inode);
492 err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
495 return translate_error(fs, ino, err);
500 static int update_atime(ext2_filsys fs, ext2_ino_t ino)
503 struct ext2_inode_large inode, *pinode;
504 struct timespec atime, mtime, now;
506 if (!(fs->flags & EXT2_FLAG_RW))
508 memset(&inode, 0, sizeof(inode));
509 err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
512 return translate_error(fs, ino, err);
515 EXT4_INODE_GET_XTIME(i_atime, &atime, pinode);
516 EXT4_INODE_GET_XTIME(i_mtime, &mtime, pinode);
519 * If atime is newer than mtime and atime hasn't been updated in thirty
520 * seconds, skip the atime update. Same idea as Linux "relatime".
522 if (atime.tv_sec >= mtime.tv_sec && atime.tv_sec >= now.tv_sec - 30)
524 EXT4_INODE_SET_XTIME(i_atime, &now, &inode);
526 err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
529 return translate_error(fs, ino, err);
534 static int update_mtime(ext2_filsys fs, ext2_ino_t ino,
535 struct ext2_inode_large *pinode)
538 struct ext2_inode_large inode;
543 EXT4_INODE_SET_XTIME(i_mtime, &now, pinode);
544 EXT4_INODE_SET_XTIME(i_ctime, &now, pinode);
545 increment_version(pinode);
549 memset(&inode, 0, sizeof(inode));
550 err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
553 return translate_error(fs, ino, err);
556 EXT4_INODE_SET_XTIME(i_mtime, &now, &inode);
557 EXT4_INODE_SET_XTIME(i_ctime, &now, &inode);
558 increment_version(&inode);
560 err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
563 return translate_error(fs, ino, err);
568 static int ext2_file_type(unsigned int mode)
570 if (LINUX_S_ISREG(mode))
571 return EXT2_FT_REG_FILE;
573 if (LINUX_S_ISDIR(mode))
576 if (LINUX_S_ISCHR(mode))
577 return EXT2_FT_CHRDEV;
579 if (LINUX_S_ISBLK(mode))
580 return EXT2_FT_BLKDEV;
582 if (LINUX_S_ISLNK(mode))
583 return EXT2_FT_SYMLINK;
585 if (LINUX_S_ISFIFO(mode))
588 if (LINUX_S_ISSOCK(mode))
594 static int fs_can_allocate(struct fuse2fs *ff, blk64_t num)
596 ext2_filsys fs = ff->fs;
599 dbg_printf("%s: Asking for %llu; alloc_all=%d total=%llu free=%llu "
600 "rsvd=%llu\n", __func__, num, ff->alloc_all_blocks,
601 ext2fs_blocks_count(fs->super),
602 ext2fs_free_blocks_count(fs->super),
603 ext2fs_r_blocks_count(fs->super));
604 if (num > ext2fs_blocks_count(fs->super))
607 if (ff->alloc_all_blocks)
611 * Different meaning for r_blocks -- libext2fs has bugs where the FS
612 * can get corrupted if it totally runs out of blocks. Avoid this
613 * by refusing to allocate any of the reserve blocks to anybody.
615 reserved = ext2fs_r_blocks_count(fs->super);
617 reserved = ext2fs_blocks_count(fs->super) / 10;
618 return ext2fs_free_blocks_count(fs->super) > reserved + num;
621 static int fs_writeable(ext2_filsys fs)
623 return (fs->flags & EXT2_FLAG_RW) && (fs->super->s_error_count == 0);
626 static int check_inum_access(ext2_filsys fs, ext2_ino_t ino, mode_t mask)
628 struct fuse_context *ctxt = fuse_get_context();
629 struct ext2_inode inode;
633 /* no writing to read-only or broken fs */
634 if ((mask & W_OK) && !fs_writeable(fs))
637 err = ext2fs_read_inode(fs, ino, &inode);
639 return translate_error(fs, ino, err);
640 perms = inode.i_mode & 0777;
642 dbg_printf("access ino=%d mask=e%s%s%s perms=0%o fuid=%d fgid=%d "
643 "uid=%d gid=%d\n", ino,
644 (mask & R_OK ? "r" : ""), (mask & W_OK ? "w" : ""),
645 (mask & X_OK ? "x" : ""), perms, inode.i_uid, inode.i_gid,
646 ctxt->uid, ctxt->gid);
648 /* existence check */
654 (inode.i_flags & EXT2_IMMUTABLE_FL))
657 /* Figure out what root's allowed to do */
658 if (ctxt->uid == 0) {
659 /* Non-file access always ok */
660 if (!LINUX_S_ISREG(inode.i_mode))
663 /* R/W access to a file always ok */
667 /* X access to a file ok if a user/group/other can X */
671 /* Trying to execute a file that's not executable. BZZT! */
675 /* allow owner, if perms match */
676 if (inode.i_uid == ctxt->uid) {
677 if ((mask & (perms >> 6)) == mask)
682 /* allow group, if perms match */
683 if (inode.i_gid == ctxt->gid) {
684 if ((mask & (perms >> 3)) == mask)
689 /* otherwise check other */
690 if ((mask & perms) == mask)
695 static void op_destroy(void *p EXT2FS_ATTR((unused)))
697 struct fuse_context *ctxt = fuse_get_context();
698 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
702 if (ff->magic != FUSE2FS_MAGIC) {
703 translate_error(global_fs, 0, EXT2_ET_BAD_MAGIC);
707 dbg_printf("%s: dev=%s\n", __func__, fs->device_name);
708 if (fs->flags & EXT2_FLAG_RW) {
709 fs->super->s_state |= EXT2_VALID_FS;
710 if (fs->super->s_error_count)
711 fs->super->s_state |= EXT2_ERROR_FS;
712 ext2fs_mark_super_dirty(fs);
713 err = ext2fs_set_gdt_csum(fs);
715 translate_error(fs, 0, err);
717 err = ext2fs_flush2(fs, 0);
719 translate_error(fs, 0, err);
723 static void *op_init(struct fuse_conn_info *conn)
725 struct fuse_context *ctxt = fuse_get_context();
726 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
730 if (ff->magic != FUSE2FS_MAGIC) {
731 translate_error(global_fs, 0, EXT2_ET_BAD_MAGIC);
735 dbg_printf("%s: dev=%s\n", __func__, fs->device_name);
736 #ifdef FUSE_CAP_IOCTL_DIR
737 conn->want |= FUSE_CAP_IOCTL_DIR;
739 if (fs->flags & EXT2_FLAG_RW) {
740 fs->super->s_mnt_count++;
741 fs->super->s_mtime = time(NULL);
742 fs->super->s_state &= ~EXT2_VALID_FS;
743 ext2fs_mark_super_dirty(fs);
744 err = ext2fs_flush2(fs, 0);
746 translate_error(fs, 0, err);
751 static blkcnt_t blocks_from_inode(ext2_filsys fs,
752 struct ext2_inode_large *inode)
757 if (ext2fs_has_feature_huge_file(fs->super))
758 b += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32;
760 if (!ext2fs_has_feature_huge_file(fs->super) ||
761 !(inode->i_flags & EXT4_HUGE_FILE_FL))
762 b *= fs->blocksize / 512;
763 b *= EXT2FS_CLUSTER_RATIO(fs);
768 static int stat_inode(ext2_filsys fs, ext2_ino_t ino, struct stat *statbuf)
770 struct ext2_inode_large inode;
776 memset(&inode, 0, sizeof(inode));
777 err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
780 return translate_error(fs, ino, err);
782 memcpy(&fakedev, fs->super->s_uuid, sizeof(fakedev));
783 statbuf->st_dev = fakedev;
784 statbuf->st_ino = ino;
785 statbuf->st_mode = inode.i_mode;
786 statbuf->st_nlink = inode.i_links_count;
787 statbuf->st_uid = inode.i_uid;
788 statbuf->st_gid = inode.i_gid;
789 statbuf->st_size = EXT2_I_SIZE(&inode);
790 statbuf->st_blksize = fs->blocksize;
791 statbuf->st_blocks = blocks_from_inode(fs, &inode);
792 EXT4_INODE_GET_XTIME(i_atime, &tv, &inode);
793 statbuf->st_atime = tv.tv_sec;
794 EXT4_INODE_GET_XTIME(i_mtime, &tv, &inode);
795 statbuf->st_mtime = tv.tv_sec;
796 EXT4_INODE_GET_XTIME(i_ctime, &tv, &inode);
797 statbuf->st_ctime = tv.tv_sec;
798 if (LINUX_S_ISCHR(inode.i_mode) ||
799 LINUX_S_ISBLK(inode.i_mode)) {
800 if (inode.i_block[0])
801 statbuf->st_rdev = inode.i_block[0];
803 statbuf->st_rdev = inode.i_block[1];
809 static int op_getattr(const char *path, struct stat *statbuf)
811 struct fuse_context *ctxt = fuse_get_context();
812 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
818 FUSE2FS_CHECK_CONTEXT(ff);
820 dbg_printf("%s: path=%s\n", __func__, path);
821 pthread_mutex_lock(&ff->bfl);
822 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
824 ret = translate_error(fs, 0, err);
827 ret = stat_inode(fs, ino, statbuf);
829 pthread_mutex_unlock(&ff->bfl);
833 static int op_readlink(const char *path, char *buf, size_t len)
835 struct fuse_context *ctxt = fuse_get_context();
836 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
840 struct ext2_inode inode;
845 FUSE2FS_CHECK_CONTEXT(ff);
847 dbg_printf("%s: path=%s\n", __func__, path);
848 pthread_mutex_lock(&ff->bfl);
849 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
850 if (err || ino == 0) {
851 ret = translate_error(fs, 0, err);
855 err = ext2fs_read_inode(fs, ino, &inode);
857 ret = translate_error(fs, ino, err);
861 if (!LINUX_S_ISLNK(inode.i_mode)) {
867 if (inode.i_size < len)
869 if (ext2fs_is_fast_symlink(&inode))
870 memcpy(buf, (char *)inode.i_block, len);
872 /* big/inline symlink */
874 err = ext2fs_file_open(fs, ino, 0, &file);
876 ret = translate_error(fs, ino, err);
880 err = ext2fs_file_read(file, buf, len, &got);
881 if (err || got != len) {
882 ext2fs_file_close(file);
883 ret = translate_error(fs, ino, err);
888 err = ext2fs_file_close(file);
892 ret = translate_error(fs, ino, err);
898 if (fs_writeable(fs)) {
899 ret = update_atime(fs, ino);
905 pthread_mutex_unlock(&ff->bfl);
909 static int op_mknod(const char *path, mode_t mode, dev_t dev)
911 struct fuse_context *ctxt = fuse_get_context();
912 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
914 ext2_ino_t parent, child;
919 struct ext2_inode_large inode;
922 FUSE2FS_CHECK_CONTEXT(ff);
924 dbg_printf("%s: path=%s mode=0%o dev=0x%x\n", __func__, path, mode,
926 temp_path = strdup(path);
931 node_name = strrchr(temp_path, '/');
940 pthread_mutex_lock(&ff->bfl);
941 if (!fs_can_allocate(ff, 2)) {
946 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
949 ret = translate_error(fs, 0, err);
953 ret = check_inum_access(fs, parent, W_OK);
959 if (LINUX_S_ISCHR(mode))
960 filetype = EXT2_FT_CHRDEV;
961 else if (LINUX_S_ISBLK(mode))
962 filetype = EXT2_FT_BLKDEV;
963 else if (LINUX_S_ISFIFO(mode))
964 filetype = EXT2_FT_FIFO;
965 else if (LINUX_S_ISSOCK(mode))
966 filetype = EXT2_FT_SOCK;
972 err = ext2fs_new_inode(fs, parent, mode, 0, &child);
974 ret = translate_error(fs, 0, err);
978 dbg_printf("%s: create ino=%d/name=%s in dir=%d\n", __func__, child,
980 err = ext2fs_link(fs, parent, node_name, child, filetype);
981 if (err == EXT2_ET_DIR_NO_SPACE) {
982 err = ext2fs_expand_dir(fs, parent);
984 ret = translate_error(fs, parent, err);
988 err = ext2fs_link(fs, parent, node_name, child,
992 ret = translate_error(fs, parent, err);
996 ret = update_mtime(fs, parent, NULL);
1000 memset(&inode, 0, sizeof(inode));
1001 inode.i_mode = mode;
1004 inode.i_block[1] = dev;
1006 inode.i_block[0] = dev;
1007 inode.i_links_count = 1;
1008 inode.i_extra_isize = sizeof(struct ext2_inode_large) -
1009 EXT2_GOOD_OLD_INODE_SIZE;
1010 inode.i_uid = ctxt->uid;
1011 inode.i_gid = ctxt->gid;
1013 err = ext2fs_write_new_inode(fs, child, (struct ext2_inode *)&inode);
1015 ret = translate_error(fs, child, err);
1019 inode.i_generation = ff->next_generation++;
1021 err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode,
1024 ret = translate_error(fs, child, err);
1028 ext2fs_inode_alloc_stats2(fs, child, 1, 0);
1031 pthread_mutex_unlock(&ff->bfl);
1037 static int op_mkdir(const char *path, mode_t mode)
1039 struct fuse_context *ctxt = fuse_get_context();
1040 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1042 ext2_ino_t parent, child;
1046 struct ext2_inode_large inode;
1052 FUSE2FS_CHECK_CONTEXT(ff);
1054 dbg_printf("%s: path=%s mode=0%o\n", __func__, path, mode);
1055 temp_path = strdup(path);
1060 node_name = strrchr(temp_path, '/');
1069 pthread_mutex_lock(&ff->bfl);
1070 if (!fs_can_allocate(ff, 1)) {
1075 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
1078 ret = translate_error(fs, 0, err);
1082 ret = check_inum_access(fs, parent, W_OK);
1086 /* Is the parent dir sgid? */
1087 err = ext2fs_read_inode_full(fs, parent, (struct ext2_inode *)&inode,
1090 ret = translate_error(fs, parent, err);
1093 parent_sgid = inode.i_mode & S_ISGID;
1097 err = ext2fs_mkdir(fs, parent, 0, node_name);
1098 if (err == EXT2_ET_DIR_NO_SPACE) {
1099 err = ext2fs_expand_dir(fs, parent);
1101 ret = translate_error(fs, parent, err);
1105 err = ext2fs_mkdir(fs, parent, 0, node_name);
1108 ret = translate_error(fs, parent, err);
1112 ret = update_mtime(fs, parent, NULL);
1116 /* Still have to update the uid/gid of the dir */
1117 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
1120 ret = translate_error(fs, 0, err);
1123 dbg_printf("%s: created ino=%d/path=%s in dir=%d\n", __func__, child,
1126 memset(&inode, 0, sizeof(inode));
1127 err = ext2fs_read_inode_full(fs, child, (struct ext2_inode *)&inode,
1130 ret = translate_error(fs, child, err);
1134 inode.i_uid = ctxt->uid;
1135 inode.i_gid = ctxt->gid;
1136 inode.i_mode = LINUX_S_IFDIR | (mode & ~(S_ISUID | fs->umask)) |
1138 inode.i_generation = ff->next_generation++;
1140 err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode,
1143 ret = translate_error(fs, child, err);
1147 /* Rewrite the directory block checksum, having set i_generation */
1148 if ((inode.i_flags & EXT4_INLINE_DATA_FL) ||
1149 !ext2fs_has_feature_metadata_csum(fs->super))
1151 err = ext2fs_new_dir_block(fs, child, parent, &block);
1153 ret = translate_error(fs, child, err);
1156 err = ext2fs_bmap2(fs, child, (struct ext2_inode *)&inode, NULL, 0, 0,
1159 ret = translate_error(fs, child, err);
1162 err = ext2fs_write_dir_block4(fs, blk, block, 0, child);
1164 ret = translate_error(fs, child, err);
1169 ext2fs_free_mem(&block);
1171 pthread_mutex_unlock(&ff->bfl);
1177 static int unlink_file_by_name(ext2_filsys fs, const char *path)
1181 char *filename = strdup(path);
1185 base_name = strrchr(filename, '/');
1187 *base_name++ = '\0';
1188 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, filename,
1192 return translate_error(fs, 0, err);
1195 dir = EXT2_ROOT_INO;
1196 base_name = filename;
1199 ret = check_inum_access(fs, dir, W_OK);
1205 dbg_printf("%s: unlinking name=%s from dir=%d\n", __func__,
1207 err = ext2fs_unlink(fs, dir, base_name, 0, 0);
1210 return translate_error(fs, dir, err);
1212 return update_mtime(fs, dir, NULL);
1215 static int remove_inode(struct fuse2fs *ff, ext2_ino_t ino)
1217 ext2_filsys fs = ff->fs;
1219 struct ext2_inode_large inode;
1222 memset(&inode, 0, sizeof(inode));
1223 err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
1226 ret = translate_error(fs, ino, err);
1229 dbg_printf("%s: put ino=%d links=%d\n", __func__, ino,
1230 inode.i_links_count);
1232 switch (inode.i_links_count) {
1234 return 0; /* XXX: already done? */
1236 inode.i_links_count--;
1237 inode.i_dtime = fs->now ? fs->now : time(0);
1240 inode.i_links_count--;
1243 ret = update_ctime(fs, ino, &inode);
1247 if (inode.i_links_count)
1250 /* Nobody holds this file; free its blocks! */
1251 err = ext2fs_free_ext_attr(fs, ino, &inode);
1255 if (ext2fs_inode_has_valid_blocks2(fs, (struct ext2_inode *)&inode)) {
1256 err = ext2fs_punch(fs, ino, (struct ext2_inode *)&inode, NULL,
1259 ret = translate_error(fs, ino, err);
1264 ext2fs_inode_alloc_stats2(fs, ino, -1,
1265 LINUX_S_ISDIR(inode.i_mode));
1268 err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
1271 ret = translate_error(fs, ino, err);
1278 static int __op_unlink(struct fuse2fs *ff, const char *path)
1280 ext2_filsys fs = ff->fs;
1285 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
1287 ret = translate_error(fs, 0, err);
1291 ret = unlink_file_by_name(fs, path);
1295 ret = remove_inode(ff, ino);
1302 static int op_unlink(const char *path)
1304 struct fuse_context *ctxt = fuse_get_context();
1305 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1308 FUSE2FS_CHECK_CONTEXT(ff);
1309 pthread_mutex_lock(&ff->bfl);
1310 ret = __op_unlink(ff, path);
1311 pthread_mutex_unlock(&ff->bfl);
1320 static int rmdir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
1321 int entry EXT2FS_ATTR((unused)),
1322 struct ext2_dir_entry *dirent,
1323 int offset EXT2FS_ATTR((unused)),
1324 int blocksize EXT2FS_ATTR((unused)),
1325 char *buf EXT2FS_ATTR((unused)),
1328 struct rd_struct *rds = (struct rd_struct *) private;
1330 if (dirent->inode == 0)
1332 if (((dirent->name_len & 0xFF) == 1) && (dirent->name[0] == '.'))
1334 if (((dirent->name_len & 0xFF) == 2) && (dirent->name[0] == '.') &&
1335 (dirent->name[1] == '.')) {
1336 rds->parent = dirent->inode;
1343 static int __op_rmdir(struct fuse2fs *ff, const char *path)
1345 ext2_filsys fs = ff->fs;
1348 struct ext2_inode_large inode;
1349 struct rd_struct rds;
1352 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &child);
1354 ret = translate_error(fs, 0, err);
1357 dbg_printf("%s: rmdir path=%s ino=%d\n", __func__, path, child);
1362 err = ext2fs_dir_iterate2(fs, child, 0, 0, rmdir_proc, &rds);
1364 ret = translate_error(fs, child, err);
1368 if (rds.empty == 0) {
1373 ret = unlink_file_by_name(fs, path);
1376 /* Directories have to be "removed" twice. */
1377 ret = remove_inode(ff, child);
1380 ret = remove_inode(ff, child);
1385 dbg_printf("%s: decr dir=%d link count\n", __func__,
1387 err = ext2fs_read_inode_full(fs, rds.parent,
1388 (struct ext2_inode *)&inode,
1391 ret = translate_error(fs, rds.parent, err);
1394 if (inode.i_links_count > 1)
1395 inode.i_links_count--;
1396 ret = update_mtime(fs, rds.parent, &inode);
1399 err = ext2fs_write_inode_full(fs, rds.parent,
1400 (struct ext2_inode *)&inode,
1403 ret = translate_error(fs, rds.parent, err);
1412 static int op_rmdir(const char *path)
1414 struct fuse_context *ctxt = fuse_get_context();
1415 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1418 FUSE2FS_CHECK_CONTEXT(ff);
1419 pthread_mutex_lock(&ff->bfl);
1420 ret = __op_rmdir(ff, path);
1421 pthread_mutex_unlock(&ff->bfl);
1425 static int op_symlink(const char *src, const char *dest)
1427 struct fuse_context *ctxt = fuse_get_context();
1428 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1430 ext2_ino_t parent, child;
1434 struct ext2_inode_large inode;
1437 FUSE2FS_CHECK_CONTEXT(ff);
1439 dbg_printf("%s: symlink %s to %s\n", __func__, src, dest);
1440 temp_path = strdup(dest);
1445 node_name = strrchr(temp_path, '/');
1454 pthread_mutex_lock(&ff->bfl);
1455 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
1459 ret = translate_error(fs, 0, err);
1463 ret = check_inum_access(fs, parent, W_OK);
1468 /* Create symlink */
1469 err = ext2fs_symlink(fs, parent, 0, node_name, src);
1470 if (err == EXT2_ET_DIR_NO_SPACE) {
1471 err = ext2fs_expand_dir(fs, parent);
1473 ret = translate_error(fs, parent, err);
1477 err = ext2fs_symlink(fs, parent, 0, node_name, src);
1480 ret = translate_error(fs, parent, err);
1484 /* Update parent dir's mtime */
1485 ret = update_mtime(fs, parent, NULL);
1489 /* Still have to update the uid/gid of the symlink */
1490 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
1493 ret = translate_error(fs, 0, err);
1496 dbg_printf("%s: symlinking ino=%d/name=%s to dir=%d\n", __func__,
1497 child, node_name, parent);
1499 memset(&inode, 0, sizeof(inode));
1500 err = ext2fs_read_inode_full(fs, child, (struct ext2_inode *)&inode,
1503 ret = translate_error(fs, child, err);
1507 inode.i_uid = ctxt->uid;
1508 inode.i_gid = ctxt->gid;
1509 inode.i_generation = ff->next_generation++;
1511 err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode,
1514 ret = translate_error(fs, child, err);
1518 pthread_mutex_unlock(&ff->bfl);
1524 struct update_dotdot {
1525 ext2_ino_t new_dotdot;
1528 static int update_dotdot_helper(ext2_ino_t dir EXT2FS_ATTR((unused)),
1529 int entry EXT2FS_ATTR((unused)),
1530 struct ext2_dir_entry *dirent,
1531 int offset EXT2FS_ATTR((unused)),
1532 int blocksize EXT2FS_ATTR((unused)),
1533 char *buf EXT2FS_ATTR((unused)),
1536 struct update_dotdot *ud = priv_data;
1538 if (ext2fs_dirent_name_len(dirent) == 2 &&
1539 dirent->name[0] == '.' && dirent->name[1] == '.') {
1540 dirent->inode = ud->new_dotdot;
1541 return DIRENT_CHANGED | DIRENT_ABORT;
1547 static int op_rename(const char *from, const char *to)
1549 struct fuse_context *ctxt = fuse_get_context();
1550 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1553 ext2_ino_t from_ino, to_ino, to_dir_ino, from_dir_ino;
1554 char *temp_to = NULL, *temp_from = NULL;
1556 struct ext2_inode inode;
1557 struct update_dotdot ud;
1560 FUSE2FS_CHECK_CONTEXT(ff);
1562 dbg_printf("%s: renaming %s to %s\n", __func__, from, to);
1563 pthread_mutex_lock(&ff->bfl);
1564 if (!fs_can_allocate(ff, 5)) {
1569 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, from, &from_ino);
1570 if (err || from_ino == 0) {
1571 ret = translate_error(fs, 0, err);
1575 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, to, &to_ino);
1576 if (err && err != EXT2_ET_FILE_NOT_FOUND) {
1577 ret = translate_error(fs, 0, err);
1581 if (err == EXT2_ET_FILE_NOT_FOUND)
1584 /* Already the same file? */
1585 if (to_ino != 0 && to_ino == from_ino) {
1590 temp_to = strdup(to);
1596 temp_from = strdup(from);
1602 /* Find parent dir of the source and check write access */
1603 cp = strrchr(temp_from, '/');
1611 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_from,
1615 ret = translate_error(fs, 0, err);
1618 if (from_dir_ino == 0) {
1623 ret = check_inum_access(fs, from_dir_ino, W_OK);
1627 /* Find parent dir of the destination and check write access */
1628 cp = strrchr(temp_to, '/');
1636 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_to,
1640 ret = translate_error(fs, 0, err);
1643 if (to_dir_ino == 0) {
1648 ret = check_inum_access(fs, to_dir_ino, W_OK);
1652 /* If the target exists, unlink it first */
1654 err = ext2fs_read_inode(fs, to_ino, &inode);
1656 ret = translate_error(fs, to_ino, err);
1660 dbg_printf("%s: unlinking %s ino=%d\n", __func__,
1661 LINUX_S_ISDIR(inode.i_mode) ? "dir" : "file",
1663 if (LINUX_S_ISDIR(inode.i_mode))
1664 ret = __op_rmdir(ff, to);
1666 ret = __op_unlink(ff, to);
1671 /* Get ready to do the move */
1672 err = ext2fs_read_inode(fs, from_ino, &inode);
1674 ret = translate_error(fs, from_ino, err);
1678 /* Link in the new file */
1679 dbg_printf("%s: linking ino=%d/path=%s to dir=%d\n", __func__,
1680 from_ino, cp + 1, to_dir_ino);
1681 err = ext2fs_link(fs, to_dir_ino, cp + 1, from_ino,
1682 ext2_file_type(inode.i_mode));
1683 if (err == EXT2_ET_DIR_NO_SPACE) {
1684 err = ext2fs_expand_dir(fs, to_dir_ino);
1686 ret = translate_error(fs, to_dir_ino, err);
1690 err = ext2fs_link(fs, to_dir_ino, cp + 1, from_ino,
1691 ext2_file_type(inode.i_mode));
1694 ret = translate_error(fs, to_dir_ino, err);
1698 /* Update '..' pointer if dir */
1699 err = ext2fs_read_inode(fs, from_ino, &inode);
1701 ret = translate_error(fs, from_ino, err);
1705 if (LINUX_S_ISDIR(inode.i_mode)) {
1706 ud.new_dotdot = to_dir_ino;
1707 dbg_printf("%s: updating .. entry for dir=%d\n", __func__,
1709 err = ext2fs_dir_iterate2(fs, from_ino, 0, NULL,
1710 update_dotdot_helper, &ud);
1712 ret = translate_error(fs, from_ino, err);
1716 /* Decrease from_dir_ino's links_count */
1717 dbg_printf("%s: moving linkcount from dir=%d to dir=%d\n",
1718 __func__, from_dir_ino, to_dir_ino);
1719 err = ext2fs_read_inode(fs, from_dir_ino, &inode);
1721 ret = translate_error(fs, from_dir_ino, err);
1724 inode.i_links_count--;
1725 err = ext2fs_write_inode(fs, from_dir_ino, &inode);
1727 ret = translate_error(fs, from_dir_ino, err);
1731 /* Increase to_dir_ino's links_count */
1732 err = ext2fs_read_inode(fs, to_dir_ino, &inode);
1734 ret = translate_error(fs, to_dir_ino, err);
1737 inode.i_links_count++;
1738 err = ext2fs_write_inode(fs, to_dir_ino, &inode);
1740 ret = translate_error(fs, to_dir_ino, err);
1745 /* Update timestamps */
1746 ret = update_ctime(fs, from_ino, NULL);
1750 ret = update_mtime(fs, to_dir_ino, NULL);
1754 /* Remove the old file */
1755 ret = unlink_file_by_name(fs, from);
1759 /* Flush the whole mess out */
1760 err = ext2fs_flush2(fs, 0);
1762 ret = translate_error(fs, 0, err);
1768 pthread_mutex_unlock(&ff->bfl);
1772 static int op_link(const char *src, const char *dest)
1774 struct fuse_context *ctxt = fuse_get_context();
1775 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1780 ext2_ino_t parent, ino;
1781 struct ext2_inode_large inode;
1784 FUSE2FS_CHECK_CONTEXT(ff);
1786 dbg_printf("%s: src=%s dest=%s\n", __func__, src, dest);
1787 temp_path = strdup(dest);
1792 node_name = strrchr(temp_path, '/');
1801 pthread_mutex_lock(&ff->bfl);
1802 if (!fs_can_allocate(ff, 2)) {
1807 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
1815 ret = check_inum_access(fs, parent, W_OK);
1820 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, src, &ino);
1821 if (err || ino == 0) {
1822 ret = translate_error(fs, 0, err);
1826 memset(&inode, 0, sizeof(inode));
1827 err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
1830 ret = translate_error(fs, ino, err);
1834 inode.i_links_count++;
1835 ret = update_ctime(fs, ino, &inode);
1839 err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
1842 ret = translate_error(fs, ino, err);
1846 dbg_printf("%s: linking ino=%d/name=%s to dir=%d\n", __func__, ino,
1848 err = ext2fs_link(fs, parent, node_name, ino,
1849 ext2_file_type(inode.i_mode));
1850 if (err == EXT2_ET_DIR_NO_SPACE) {
1851 err = ext2fs_expand_dir(fs, parent);
1853 ret = translate_error(fs, parent, err);
1857 err = ext2fs_link(fs, parent, node_name, ino,
1858 ext2_file_type(inode.i_mode));
1861 ret = translate_error(fs, parent, err);
1865 ret = update_mtime(fs, parent, NULL);
1870 pthread_mutex_unlock(&ff->bfl);
1876 static int op_chmod(const char *path, mode_t mode)
1878 struct fuse_context *ctxt = fuse_get_context();
1879 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1883 struct ext2_inode_large inode;
1886 FUSE2FS_CHECK_CONTEXT(ff);
1888 pthread_mutex_lock(&ff->bfl);
1889 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
1891 ret = translate_error(fs, 0, err);
1894 dbg_printf("%s: path=%s mode=0%o ino=%d\n", __func__, path, mode, ino);
1896 memset(&inode, 0, sizeof(inode));
1897 err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
1900 ret = translate_error(fs, ino, err);
1904 if (ctxt->uid != 0 && ctxt->uid != inode.i_uid) {
1910 * XXX: We should really check that the inode gid is not in /any/
1911 * of the user's groups, but FUSE only tells us about the primary
1914 if (ctxt->uid != 0 && ctxt->gid != inode.i_gid)
1917 inode.i_mode &= ~0xFFF;
1918 inode.i_mode |= mode & 0xFFF;
1919 ret = update_ctime(fs, ino, &inode);
1923 err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
1926 ret = translate_error(fs, ino, err);
1931 pthread_mutex_unlock(&ff->bfl);
1935 static int op_chown(const char *path, uid_t owner, gid_t group)
1937 struct fuse_context *ctxt = fuse_get_context();
1938 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1942 struct ext2_inode_large inode;
1945 FUSE2FS_CHECK_CONTEXT(ff);
1947 pthread_mutex_lock(&ff->bfl);
1948 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
1950 ret = translate_error(fs, 0, err);
1953 dbg_printf("%s: path=%s owner=%d group=%d ino=%d\n", __func__,
1954 path, owner, group, ino);
1956 memset(&inode, 0, sizeof(inode));
1957 err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
1960 ret = translate_error(fs, ino, err);
1964 /* FUSE seems to feed us ~0 to mean "don't change" */
1965 if (owner != (uid_t) ~0) {
1966 /* Only root gets to change UID. */
1967 if (ctxt->uid != 0 &&
1968 !(inode.i_uid == ctxt->uid && owner == ctxt->uid)) {
1972 inode.i_uid = owner;
1975 if (group != (gid_t) ~0) {
1976 /* Only root or the owner get to change GID. */
1977 if (ctxt->uid != 0 && inode.i_uid != ctxt->uid) {
1982 /* XXX: We /should/ check group membership but FUSE */
1983 inode.i_gid = group;
1986 ret = update_ctime(fs, ino, &inode);
1990 err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
1993 ret = translate_error(fs, ino, err);
1998 pthread_mutex_unlock(&ff->bfl);
2002 static int op_truncate(const char *path, off_t len)
2004 struct fuse_context *ctxt = fuse_get_context();
2005 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2012 FUSE2FS_CHECK_CONTEXT(ff);
2014 pthread_mutex_lock(&ff->bfl);
2015 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2016 if (err || ino == 0) {
2017 ret = translate_error(fs, 0, err);
2020 dbg_printf("%s: ino=%d len=%jd\n", __func__, ino, len);
2022 ret = check_inum_access(fs, ino, W_OK);
2026 err = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &file);
2028 ret = translate_error(fs, ino, err);
2032 err = ext2fs_file_set_size2(file, len);
2034 ret = translate_error(fs, ino, err);
2039 err = ext2fs_file_close(file);
2043 ret = translate_error(fs, ino, err);
2047 ret = update_mtime(fs, ino, NULL);
2050 pthread_mutex_unlock(&ff->bfl);
2055 static void detect_linux_executable_open(int kernel_flags, int *access_check,
2056 int *e2fs_open_flags)
2059 * On Linux, execve will bleed __FMODE_EXEC into the file mode flags,
2060 * and FUSE is more than happy to let that slip through.
2062 if (kernel_flags & 0x20) {
2063 *access_check = X_OK;
2064 *e2fs_open_flags &= ~EXT2_FILE_WRITE;
2068 static void detect_linux_executable_open(int kernel_flags, int *access_check,
2069 int *e2fs_open_flags)
2073 #endif /* __linux__ */
2075 static int __op_open(struct fuse2fs *ff, const char *path,
2076 struct fuse_file_info *fp)
2078 ext2_filsys fs = ff->fs;
2080 struct fuse2fs_file_handle *file;
2081 int check = 0, ret = 0;
2083 dbg_printf("%s: path=%s\n", __func__, path);
2084 err = ext2fs_get_mem(sizeof(*file), &file);
2086 return translate_error(fs, 0, err);
2087 file->magic = FUSE2FS_FILE_MAGIC;
2089 file->open_flags = 0;
2090 switch (fp->flags & O_ACCMODE) {
2096 file->open_flags |= EXT2_FILE_WRITE;
2099 check = R_OK | W_OK;
2100 file->open_flags |= EXT2_FILE_WRITE;
2104 detect_linux_executable_open(fp->flags, &check, &file->open_flags);
2106 if (fp->flags & O_CREAT)
2107 file->open_flags |= EXT2_FILE_CREATE;
2109 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &file->ino);
2110 if (err || file->ino == 0) {
2111 ret = translate_error(fs, 0, err);
2114 dbg_printf("%s: ino=%d\n", __func__, file->ino);
2116 ret = check_inum_access(fs, file->ino, check);
2119 * In a regular (Linux) fs driver, the kernel will open
2120 * binaries for reading if the user has --x privileges (i.e.
2121 * execute without read). Since the kernel doesn't have any
2122 * way to tell us if it's opening a file via execve, we'll
2123 * just assume that allowing access is ok if asking for ro mode
2124 * fails but asking for x mode succeeds. Of course we can
2125 * also employ undocumented hacks (see above).
2127 if (check == R_OK) {
2128 ret = check_inum_access(fs, file->ino, X_OK);
2134 fp->fh = (uintptr_t)file;
2138 ext2fs_free_mem(&file);
2142 static int op_open(const char *path, struct fuse_file_info *fp)
2144 struct fuse_context *ctxt = fuse_get_context();
2145 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2148 FUSE2FS_CHECK_CONTEXT(ff);
2149 pthread_mutex_lock(&ff->bfl);
2150 ret = __op_open(ff, path, fp);
2151 pthread_mutex_unlock(&ff->bfl);
2155 static int op_read(const char *path EXT2FS_ATTR((unused)), char *buf,
2156 size_t len, off_t offset,
2157 struct fuse_file_info *fp)
2159 struct fuse_context *ctxt = fuse_get_context();
2160 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2161 struct fuse2fs_file_handle *fh =
2162 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2166 unsigned int got = 0;
2169 FUSE2FS_CHECK_CONTEXT(ff);
2171 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2172 dbg_printf("%s: ino=%d off=%jd len=%jd\n", __func__, fh->ino, offset,
2174 pthread_mutex_lock(&ff->bfl);
2175 err = ext2fs_file_open(fs, fh->ino, fh->open_flags, &efp);
2177 ret = translate_error(fs, fh->ino, err);
2181 err = ext2fs_file_llseek(efp, offset, SEEK_SET, NULL);
2183 ret = translate_error(fs, fh->ino, err);
2187 err = ext2fs_file_read(efp, buf, len, &got);
2189 ret = translate_error(fs, fh->ino, err);
2194 err = ext2fs_file_close(efp);
2198 ret = translate_error(fs, fh->ino, err);
2202 if (fs_writeable(fs)) {
2203 ret = update_atime(fs, fh->ino);
2208 pthread_mutex_unlock(&ff->bfl);
2209 return got ? (int) got : ret;
2212 static int op_write(const char *path EXT2FS_ATTR((unused)),
2213 const char *buf, size_t len, off_t offset,
2214 struct fuse_file_info *fp)
2216 struct fuse_context *ctxt = fuse_get_context();
2217 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2218 struct fuse2fs_file_handle *fh =
2219 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2223 unsigned int got = 0;
2226 FUSE2FS_CHECK_CONTEXT(ff);
2228 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2229 dbg_printf("%s: ino=%d off=%jd len=%jd\n", __func__, fh->ino, offset,
2231 pthread_mutex_lock(&ff->bfl);
2232 if (!fs_writeable(fs)) {
2237 if (!fs_can_allocate(ff, len / fs->blocksize)) {
2242 err = ext2fs_file_open(fs, fh->ino, fh->open_flags, &efp);
2244 ret = translate_error(fs, fh->ino, err);
2248 err = ext2fs_file_llseek(efp, offset, SEEK_SET, NULL);
2250 ret = translate_error(fs, fh->ino, err);
2254 err = ext2fs_file_write(efp, buf, len, &got);
2256 ret = translate_error(fs, fh->ino, err);
2260 err = ext2fs_file_flush(efp);
2263 ret = translate_error(fs, fh->ino, err);
2268 err = ext2fs_file_close(efp);
2272 ret = translate_error(fs, fh->ino, err);
2276 ret = update_mtime(fs, fh->ino, NULL);
2281 pthread_mutex_unlock(&ff->bfl);
2282 return got ? (int) got : ret;
2285 static int op_release(const char *path EXT2FS_ATTR((unused)),
2286 struct fuse_file_info *fp)
2288 struct fuse_context *ctxt = fuse_get_context();
2289 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2290 struct fuse2fs_file_handle *fh =
2291 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2296 FUSE2FS_CHECK_CONTEXT(ff);
2298 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2299 dbg_printf("%s: ino=%d\n", __func__, fh->ino);
2300 pthread_mutex_lock(&ff->bfl);
2301 if (fs_writeable(fs) && fh->open_flags & EXT2_FILE_WRITE) {
2302 err = ext2fs_flush2(fs, EXT2_FLAG_FLUSH_NO_SYNC);
2304 ret = translate_error(fs, fh->ino, err);
2307 pthread_mutex_unlock(&ff->bfl);
2309 ext2fs_free_mem(&fh);
2314 static int op_fsync(const char *path EXT2FS_ATTR((unused)),
2315 int datasync EXT2FS_ATTR((unused)),
2316 struct fuse_file_info *fp)
2318 struct fuse_context *ctxt = fuse_get_context();
2319 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2320 struct fuse2fs_file_handle *fh =
2321 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2326 FUSE2FS_CHECK_CONTEXT(ff);
2328 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2329 dbg_printf("%s: ino=%d\n", __func__, fh->ino);
2330 /* For now, flush everything, even if it's slow */
2331 pthread_mutex_lock(&ff->bfl);
2332 if (fs_writeable(fs) && fh->open_flags & EXT2_FILE_WRITE) {
2333 err = ext2fs_flush2(fs, 0);
2335 ret = translate_error(fs, fh->ino, err);
2337 pthread_mutex_unlock(&ff->bfl);
2342 static int op_statfs(const char *path EXT2FS_ATTR((unused)),
2343 struct statvfs *buf)
2345 struct fuse_context *ctxt = fuse_get_context();
2346 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2349 blk64_t overhead, reserved, free;
2351 FUSE2FS_CHECK_CONTEXT(ff);
2353 dbg_printf("%s: path=%s\n", __func__, path);
2354 buf->f_bsize = fs->blocksize;
2360 overhead = fs->desc_blocks +
2361 fs->group_desc_count *
2362 (fs->inode_blocks_per_group + 2);
2363 reserved = ext2fs_r_blocks_count(fs->super);
2365 reserved = ext2fs_blocks_count(fs->super) / 10;
2366 free = ext2fs_free_blocks_count(fs->super);
2368 buf->f_blocks = ext2fs_blocks_count(fs->super) - overhead;
2369 buf->f_bfree = free;
2370 if (free < reserved)
2373 buf->f_bavail = free - reserved;
2374 buf->f_files = fs->super->s_inodes_count;
2375 buf->f_ffree = fs->super->s_free_inodes_count;
2376 buf->f_favail = fs->super->s_free_inodes_count;
2377 f = (uint64_t *)fs->super->s_uuid;
2383 if (fs->flags & EXT2_FLAG_RW)
2384 buf->f_flag |= ST_RDONLY;
2385 buf->f_namemax = EXT2_NAME_LEN;
2390 typedef errcode_t (*xattr_xlate_get)(void **cooked_buf, size_t *cooked_sz,
2391 const void *raw_buf, size_t raw_sz);
2392 typedef errcode_t (*xattr_xlate_set)(const void *cooked_buf, size_t cooked_sz,
2393 const void **raw_buf, size_t *raw_sz);
2394 struct xattr_translate {
2396 xattr_xlate_get get;
2397 xattr_xlate_set set;
2400 #define XATTR_TRANSLATOR(p, g, s) \
2402 .get = (xattr_xlate_get)(g), \
2403 .set = (xattr_xlate_set)(s)}
2405 static struct xattr_translate xattr_translators[] = {
2406 #ifdef TRANSLATE_LINUX_ACLS
2407 XATTR_TRANSLATOR(ACL_EA_ACCESS, ext4_to_fuse_acl, fuse_to_ext4_acl),
2408 XATTR_TRANSLATOR(ACL_EA_DEFAULT, ext4_to_fuse_acl, fuse_to_ext4_acl),
2410 XATTR_TRANSLATOR(NULL, NULL, NULL),
2412 #undef XATTR_TRANSLATOR
2414 static int op_getxattr(const char *path, const char *key, char *value,
2417 struct fuse_context *ctxt = fuse_get_context();
2418 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2420 struct ext2_xattr_handle *h;
2421 struct xattr_translate *xt;
2428 FUSE2FS_CHECK_CONTEXT(ff);
2430 pthread_mutex_lock(&ff->bfl);
2431 if (!ext2fs_has_feature_xattr(fs->super)) {
2436 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2437 if (err || ino == 0) {
2438 ret = translate_error(fs, 0, err);
2441 dbg_printf("%s: ino=%d\n", __func__, ino);
2443 ret = check_inum_access(fs, ino, R_OK);
2447 err = ext2fs_xattrs_open(fs, ino, &h);
2449 ret = translate_error(fs, ino, err);
2453 err = ext2fs_xattrs_read(h);
2455 ret = translate_error(fs, ino, err);
2459 err = ext2fs_xattr_get(h, key, &ptr, &plen);
2461 ret = translate_error(fs, ino, err);
2465 for (xt = xattr_translators; xt->prefix != NULL; xt++) {
2466 if (strncmp(key, xt->prefix, strlen(xt->prefix)) == 0) {
2467 err = xt->get(&cptr, &clen, ptr, plen);
2470 ext2fs_free_mem(&ptr);
2478 } else if (len < plen) {
2481 memcpy(value, ptr, plen);
2486 ext2fs_free_mem(&ptr);
2488 err = ext2fs_xattrs_close(&h);
2490 ret = translate_error(fs, ino, err);
2492 pthread_mutex_unlock(&ff->bfl);
2497 static int count_buffer_space(char *name, char *value EXT2FS_ATTR((unused)),
2498 size_t value_len EXT2FS_ATTR((unused)),
2501 unsigned int *x = data;
2503 *x = *x + strlen(name) + 1;
2507 static int copy_names(char *name, char *value EXT2FS_ATTR((unused)),
2508 size_t value_len EXT2FS_ATTR((unused)), void *data)
2512 strncpy(*b, name, strlen(name));
2513 *b = *b + strlen(name) + 1;
2518 static int op_listxattr(const char *path, char *names, size_t len)
2520 struct fuse_context *ctxt = fuse_get_context();
2521 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2523 struct ext2_xattr_handle *h;
2529 FUSE2FS_CHECK_CONTEXT(ff);
2531 pthread_mutex_lock(&ff->bfl);
2532 if (!ext2fs_has_feature_xattr(fs->super)) {
2537 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2538 if (err || ino == 0) {
2539 ret = translate_error(fs, ino, err);
2542 dbg_printf("%s: ino=%d\n", __func__, ino);
2544 ret = check_inum_access(fs, ino, R_OK);
2548 err = ext2fs_xattrs_open(fs, ino, &h);
2550 ret = translate_error(fs, ino, err);
2554 err = ext2fs_xattrs_read(h);
2556 ret = translate_error(fs, ino, err);
2560 /* Count buffer space needed for names */
2562 err = ext2fs_xattrs_iterate(h, count_buffer_space, &bufsz);
2564 ret = translate_error(fs, ino, err);
2571 } else if (len < bufsz) {
2576 /* Copy names out */
2577 memset(names, 0, len);
2578 err = ext2fs_xattrs_iterate(h, copy_names, &names);
2580 ret = translate_error(fs, ino, err);
2585 err = ext2fs_xattrs_close(&h);
2587 ret = translate_error(fs, ino, err);
2589 pthread_mutex_unlock(&ff->bfl);
2594 static int op_setxattr(const char *path EXT2FS_ATTR((unused)),
2595 const char *key, const char *value,
2596 size_t len, int flags EXT2FS_ATTR((unused)))
2598 struct fuse_context *ctxt = fuse_get_context();
2599 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2601 struct ext2_xattr_handle *h;
2602 struct xattr_translate *xt;
2609 FUSE2FS_CHECK_CONTEXT(ff);
2611 pthread_mutex_lock(&ff->bfl);
2612 if (!ext2fs_has_feature_xattr(fs->super)) {
2617 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2618 if (err || ino == 0) {
2619 ret = translate_error(fs, 0, err);
2622 dbg_printf("%s: ino=%d\n", __func__, ino);
2624 ret = check_inum_access(fs, ino, W_OK);
2625 if (ret == -EACCES) {
2631 err = ext2fs_xattrs_open(fs, ino, &h);
2633 ret = translate_error(fs, ino, err);
2637 err = ext2fs_xattrs_read(h);
2639 ret = translate_error(fs, ino, err);
2645 for (xt = xattr_translators; xt->prefix != NULL; xt++) {
2646 if (strncmp(key, xt->prefix, strlen(xt->prefix)) == 0) {
2647 err = xt->set(value, len, &cvalue, &clen);
2653 err = ext2fs_xattr_set(h, key, cvalue, clen);
2655 ret = translate_error(fs, ino, err);
2659 ret = update_ctime(fs, ino, NULL);
2661 if (cvalue != value)
2662 ext2fs_free_mem(&cvalue);
2664 err = ext2fs_xattrs_close(&h);
2666 ret = translate_error(fs, ino, err);
2668 pthread_mutex_unlock(&ff->bfl);
2673 static int op_removexattr(const char *path, const char *key)
2675 struct fuse_context *ctxt = fuse_get_context();
2676 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2678 struct ext2_xattr_handle *h;
2683 FUSE2FS_CHECK_CONTEXT(ff);
2685 pthread_mutex_lock(&ff->bfl);
2686 if (!ext2fs_has_feature_xattr(fs->super)) {
2691 if (!fs_can_allocate(ff, 1)) {
2696 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2697 if (err || ino == 0) {
2698 ret = translate_error(fs, 0, err);
2701 dbg_printf("%s: ino=%d\n", __func__, ino);
2703 ret = check_inum_access(fs, ino, W_OK);
2707 err = ext2fs_xattrs_open(fs, ino, &h);
2709 ret = translate_error(fs, ino, err);
2713 err = ext2fs_xattrs_read(h);
2715 ret = translate_error(fs, ino, err);
2719 err = ext2fs_xattr_remove(h, key);
2721 ret = translate_error(fs, ino, err);
2725 ret = update_ctime(fs, ino, NULL);
2727 err = ext2fs_xattrs_close(&h);
2729 ret = translate_error(fs, ino, err);
2731 pthread_mutex_unlock(&ff->bfl);
2736 struct readdir_iter {
2738 fuse_fill_dir_t func;
2741 static int op_readdir_iter(ext2_ino_t dir EXT2FS_ATTR((unused)),
2742 int entry EXT2FS_ATTR((unused)),
2743 struct ext2_dir_entry *dirent,
2744 int offset EXT2FS_ATTR((unused)),
2745 int blocksize EXT2FS_ATTR((unused)),
2746 char *buf EXT2FS_ATTR((unused)), void *data)
2748 struct readdir_iter *i = data;
2749 char namebuf[EXT2_NAME_LEN + 1];
2752 memcpy(namebuf, dirent->name, dirent->name_len & 0xFF);
2753 namebuf[dirent->name_len & 0xFF] = 0;
2754 ret = i->func(i->buf, namebuf, NULL, 0);
2756 return DIRENT_ABORT;
2761 static int op_readdir(const char *path EXT2FS_ATTR((unused)),
2762 void *buf, fuse_fill_dir_t fill_func,
2763 off_t offset EXT2FS_ATTR((unused)),
2764 struct fuse_file_info *fp)
2766 struct fuse_context *ctxt = fuse_get_context();
2767 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2768 struct fuse2fs_file_handle *fh =
2769 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2772 struct readdir_iter i;
2775 FUSE2FS_CHECK_CONTEXT(ff);
2777 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2778 dbg_printf("%s: ino=%d\n", __func__, fh->ino);
2779 pthread_mutex_lock(&ff->bfl);
2782 err = ext2fs_dir_iterate2(fs, fh->ino, 0, NULL, op_readdir_iter, &i);
2784 ret = translate_error(fs, fh->ino, err);
2788 if (fs_writeable(fs)) {
2789 ret = update_atime(fs, fh->ino);
2794 pthread_mutex_unlock(&ff->bfl);
2798 static int op_access(const char *path, int mask)
2800 struct fuse_context *ctxt = fuse_get_context();
2801 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2807 FUSE2FS_CHECK_CONTEXT(ff);
2809 dbg_printf("%s: path=%s mask=0x%x\n", __func__, path, mask);
2810 pthread_mutex_lock(&ff->bfl);
2811 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2812 if (err || ino == 0) {
2813 ret = translate_error(fs, 0, err);
2817 ret = check_inum_access(fs, ino, mask);
2822 pthread_mutex_unlock(&ff->bfl);
2826 static int op_create(const char *path, mode_t mode, struct fuse_file_info *fp)
2828 struct fuse_context *ctxt = fuse_get_context();
2829 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2831 ext2_ino_t parent, child;
2836 struct ext2_inode_large inode;
2839 FUSE2FS_CHECK_CONTEXT(ff);
2841 dbg_printf("%s: path=%s mode=0%o\n", __func__, path, mode);
2842 temp_path = strdup(path);
2847 node_name = strrchr(temp_path, '/');
2856 pthread_mutex_lock(&ff->bfl);
2857 if (!fs_can_allocate(ff, 1)) {
2862 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
2865 ret = translate_error(fs, 0, err);
2869 ret = check_inum_access(fs, parent, W_OK);
2875 filetype = ext2_file_type(mode);
2877 err = ext2fs_new_inode(fs, parent, mode, 0, &child);
2879 ret = translate_error(fs, parent, err);
2883 dbg_printf("%s: creating ino=%d/name=%s in dir=%d\n", __func__, child,
2885 err = ext2fs_link(fs, parent, node_name, child, filetype);
2886 if (err == EXT2_ET_DIR_NO_SPACE) {
2887 err = ext2fs_expand_dir(fs, parent);
2889 ret = translate_error(fs, parent, err);
2893 err = ext2fs_link(fs, parent, node_name, child,
2897 ret = translate_error(fs, parent, err);
2901 ret = update_mtime(fs, parent, NULL);
2905 memset(&inode, 0, sizeof(inode));
2906 inode.i_mode = mode;
2907 inode.i_links_count = 1;
2908 inode.i_extra_isize = sizeof(struct ext2_inode_large) -
2909 EXT2_GOOD_OLD_INODE_SIZE;
2910 inode.i_uid = ctxt->uid;
2911 inode.i_gid = ctxt->gid;
2912 if (ext2fs_has_feature_extents(fs->super)) {
2913 ext2_extent_handle_t handle;
2915 inode.i_flags &= ~EXT4_EXTENTS_FL;
2916 ret = ext2fs_extent_open2(fs, child,
2917 (struct ext2_inode *)&inode, &handle);
2920 ext2fs_extent_free(handle);
2923 err = ext2fs_write_new_inode(fs, child, (struct ext2_inode *)&inode);
2925 ret = translate_error(fs, child, err);
2929 inode.i_generation = ff->next_generation++;
2931 err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode,
2934 ret = translate_error(fs, child, err);
2938 ext2fs_inode_alloc_stats2(fs, child, 1, 0);
2940 ret = __op_open(ff, path, fp);
2944 pthread_mutex_unlock(&ff->bfl);
2950 static int op_ftruncate(const char *path EXT2FS_ATTR((unused)),
2951 off_t len, struct fuse_file_info *fp)
2953 struct fuse_context *ctxt = fuse_get_context();
2954 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2955 struct fuse2fs_file_handle *fh =
2956 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2962 FUSE2FS_CHECK_CONTEXT(ff);
2964 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2965 dbg_printf("%s: ino=%d len=%jd\n", __func__, fh->ino, len);
2966 pthread_mutex_lock(&ff->bfl);
2967 if (!fs_writeable(fs)) {
2972 err = ext2fs_file_open(fs, fh->ino, fh->open_flags, &efp);
2974 ret = translate_error(fs, fh->ino, err);
2978 err = ext2fs_file_set_size2(efp, len);
2980 ret = translate_error(fs, fh->ino, err);
2985 err = ext2fs_file_close(efp);
2989 ret = translate_error(fs, fh->ino, err);
2993 ret = update_mtime(fs, fh->ino, NULL);
2998 pthread_mutex_unlock(&ff->bfl);
3002 static int op_fgetattr(const char *path EXT2FS_ATTR((unused)),
3003 struct stat *statbuf,
3004 struct fuse_file_info *fp)
3006 struct fuse_context *ctxt = fuse_get_context();
3007 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3009 struct fuse2fs_file_handle *fh =
3010 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
3013 FUSE2FS_CHECK_CONTEXT(ff);
3015 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3016 dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3017 pthread_mutex_lock(&ff->bfl);
3018 ret = stat_inode(fs, fh->ino, statbuf);
3019 pthread_mutex_unlock(&ff->bfl);
3024 static int op_utimens(const char *path, const struct timespec ctv[2])
3026 struct fuse_context *ctxt = fuse_get_context();
3027 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3028 struct timespec tv[2];
3032 struct ext2_inode_large inode;
3035 FUSE2FS_CHECK_CONTEXT(ff);
3037 pthread_mutex_lock(&ff->bfl);
3038 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
3040 ret = translate_error(fs, 0, err);
3043 dbg_printf("%s: ino=%d\n", __func__, ino);
3045 ret = check_inum_access(fs, ino, W_OK);
3049 memset(&inode, 0, sizeof(inode));
3050 err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
3053 ret = translate_error(fs, ino, err);
3060 if (tv[0].tv_nsec == UTIME_NOW)
3062 if (tv[1].tv_nsec == UTIME_NOW)
3064 #endif /* UTIME_NOW */
3066 if (tv[0].tv_nsec != UTIME_OMIT)
3067 EXT4_INODE_SET_XTIME(i_atime, tv, &inode);
3068 if (tv[1].tv_nsec != UTIME_OMIT)
3069 EXT4_INODE_SET_XTIME(i_mtime, tv + 1, &inode);
3070 #endif /* UTIME_OMIT */
3071 ret = update_ctime(fs, ino, &inode);
3075 err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
3078 ret = translate_error(fs, ino, err);
3083 pthread_mutex_unlock(&ff->bfl);
3087 #ifdef SUPPORT_I_FLAGS
3088 static int ioctl_getflags(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3092 struct ext2_inode_large inode;
3094 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3095 dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3096 memset(&inode, 0, sizeof(inode));
3097 err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3100 return translate_error(fs, fh->ino, err);
3102 *(__u32 *)data = inode.i_flags & EXT2_FL_USER_VISIBLE;
3106 #define FUSE2FS_MODIFIABLE_IFLAGS \
3107 (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL | EXT2_NODUMP_FL | \
3108 EXT2_NOATIME_FL | EXT3_JOURNAL_DATA_FL | EXT2_DIRSYNC_FL | \
3111 static int ioctl_setflags(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3115 struct ext2_inode_large inode;
3117 __u32 flags = *(__u32 *)data;
3118 struct fuse_context *ctxt = fuse_get_context();
3120 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3121 dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3122 memset(&inode, 0, sizeof(inode));
3123 err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3126 return translate_error(fs, fh->ino, err);
3128 if (ctxt->uid != 0 && inode.i_uid != ctxt->uid)
3131 if ((inode.i_flags ^ flags) & ~FUSE2FS_MODIFIABLE_IFLAGS)
3134 inode.i_flags = (inode.i_flags & ~FUSE2FS_MODIFIABLE_IFLAGS) |
3135 (flags & FUSE2FS_MODIFIABLE_IFLAGS);
3137 ret = update_ctime(fs, fh->ino, &inode);
3141 err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3144 return translate_error(fs, fh->ino, err);
3149 static int ioctl_getversion(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3153 struct ext2_inode_large inode;
3155 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3156 dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3157 memset(&inode, 0, sizeof(inode));
3158 err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3161 return translate_error(fs, fh->ino, err);
3163 *(__u32 *)data = inode.i_generation;
3167 static int ioctl_setversion(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3171 struct ext2_inode_large inode;
3173 __u32 generation = *(__u32 *)data;
3174 struct fuse_context *ctxt = fuse_get_context();
3176 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3177 dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3178 memset(&inode, 0, sizeof(inode));
3179 err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3182 return translate_error(fs, fh->ino, err);
3184 if (ctxt->uid != 0 && inode.i_uid != ctxt->uid)
3187 inode.i_generation = generation;
3189 ret = update_ctime(fs, fh->ino, &inode);
3193 err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3196 return translate_error(fs, fh->ino, err);
3200 #endif /* SUPPORT_I_FLAGS */
3203 static int ioctl_fitrim(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3206 struct fstrim_range *fr = data;
3207 blk64_t start, end, max_blocks, b, cleared;
3210 start = fr->start / fs->blocksize;
3211 end = (fr->start + fr->len - 1) / fs->blocksize;
3212 dbg_printf("%s: start=%llu end=%llu\n", __func__, start, end);
3214 if (start < fs->super->s_first_data_block)
3215 start = fs->super->s_first_data_block;
3216 if (start >= ext2fs_blocks_count(fs->super))
3217 start = ext2fs_blocks_count(fs->super) - 1;
3219 if (end < fs->super->s_first_data_block)
3220 end = fs->super->s_first_data_block;
3221 if (end >= ext2fs_blocks_count(fs->super))
3222 end = ext2fs_blocks_count(fs->super) - 1;
3225 max_blocks = 2048ULL * 1024 * 1024 / fs->blocksize;
3228 while (start <= end) {
3229 err = ext2fs_find_first_zero_block_bitmap2(fs->block_map,
3230 start, end, &start);
3234 return translate_error(fs, fh->ino, err);
3236 b = start + max_blocks < end ? start + max_blocks : end;
3237 err = ext2fs_find_first_set_block_bitmap2(fs->block_map,
3239 if (err && err != ENOENT)
3240 return translate_error(fs, fh->ino, err);
3241 if (b - start >= fr->minlen) {
3242 err = io_channel_discard(fs->io, start, b - start);
3244 return translate_error(fs, fh->ino, err);
3245 cleared += b - start;
3246 fr->len = cleared * fs->blocksize;
3255 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
3256 static int op_ioctl(const char *path EXT2FS_ATTR((unused)), int cmd,
3257 void *arg EXT2FS_ATTR((unused)),
3258 struct fuse_file_info *fp,
3259 unsigned int flags EXT2FS_ATTR((unused)), void *data)
3261 struct fuse_context *ctxt = fuse_get_context();
3262 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3263 struct fuse2fs_file_handle *fh =
3264 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
3268 FUSE2FS_CHECK_CONTEXT(ff);
3270 pthread_mutex_lock(&ff->bfl);
3271 switch ((unsigned long) cmd) {
3272 #ifdef SUPPORT_I_FLAGS
3273 case EXT2_IOC_GETFLAGS:
3274 ret = ioctl_getflags(fs, fh, data);
3276 case EXT2_IOC_SETFLAGS:
3277 ret = ioctl_setflags(fs, fh, data);
3279 case EXT2_IOC_GETVERSION:
3280 ret = ioctl_getversion(fs, fh, data);
3282 case EXT2_IOC_SETVERSION:
3283 ret = ioctl_setversion(fs, fh, data);
3288 ret = ioctl_fitrim(fs, fh, data);
3292 dbg_printf("%s: Unknown ioctl %d\n", __func__, cmd);
3295 pthread_mutex_unlock(&ff->bfl);
3299 #endif /* FUSE 28 */
3301 static int op_bmap(const char *path, size_t blocksize EXT2FS_ATTR((unused)),
3304 struct fuse_context *ctxt = fuse_get_context();
3305 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3311 FUSE2FS_CHECK_CONTEXT(ff);
3313 pthread_mutex_lock(&ff->bfl);
3314 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
3316 ret = translate_error(fs, 0, err);
3319 dbg_printf("%s: ino=%d blk=%"PRIu64"\n", __func__, ino, *idx);
3321 err = ext2fs_bmap2(fs, ino, NULL, NULL, 0, *idx, 0, (blk64_t *)idx);
3323 ret = translate_error(fs, ino, err);
3328 pthread_mutex_unlock(&ff->bfl);
3332 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
3333 # ifdef SUPPORT_FALLOCATE
3334 static int fallocate_helper(struct fuse_file_info *fp, int mode, off_t offset,
3337 struct fuse_context *ctxt = fuse_get_context();
3338 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3339 struct fuse2fs_file_handle *fh =
3340 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
3342 struct ext2_inode_large inode;
3348 FUSE2FS_CHECK_CONTEXT(ff);
3350 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3351 start = offset / fs->blocksize;
3352 end = (offset + len - 1) / fs->blocksize;
3353 dbg_printf("%s: ino=%d mode=0x%x start=%jd end=%llu\n", __func__,
3354 fh->ino, mode, offset / fs->blocksize, end);
3355 if (!fs_can_allocate(ff, len / fs->blocksize))
3358 memset(&inode, 0, sizeof(inode));
3359 err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3363 fsize = EXT2_I_SIZE(&inode);
3365 /* Allocate a bunch of blocks */
3366 flags = (mode & FL_KEEP_SIZE_FLAG ? 0 :
3367 EXT2_FALLOCATE_INIT_BEYOND_EOF);
3368 err = ext2fs_fallocate(fs, flags, fh->ino,
3369 (struct ext2_inode *)&inode,
3370 ~0ULL, start, end - start + 1);
3371 if (err && err != EXT2_ET_BLOCK_ALLOC_FAIL)
3372 return translate_error(fs, fh->ino, err);
3375 if (!(mode & FL_KEEP_SIZE_FLAG)) {
3376 if ((__u64) offset + len > fsize) {
3377 err = ext2fs_inode_size_set(fs,
3378 (struct ext2_inode *)&inode,
3381 return translate_error(fs, fh->ino, err);
3385 err = update_mtime(fs, fh->ino, &inode);
3389 err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3392 return translate_error(fs, fh->ino, err);
3397 static errcode_t clean_block_middle(ext2_filsys fs, ext2_ino_t ino,
3398 struct ext2_inode_large *inode, off_t offset,
3399 off_t len, char **buf)
3406 residue = offset % fs->blocksize;
3411 err = ext2fs_get_mem(fs->blocksize, buf);
3416 err = ext2fs_bmap2(fs, ino, (struct ext2_inode *)inode, *buf, 0,
3417 offset / fs->blocksize, &retflags, &blk);
3420 if (!blk || (retflags & BMAP_RET_UNINIT))
3423 err = io_channel_read_blk(fs->io, blk, 1, *buf);
3427 memset(*buf + residue, 0, len);
3429 return io_channel_write_blk(fs->io, blk, 1, *buf);
3432 static errcode_t clean_block_edge(ext2_filsys fs, ext2_ino_t ino,
3433 struct ext2_inode_large *inode, off_t offset,
3434 int clean_before, char **buf)
3441 residue = offset % fs->blocksize;
3446 err = ext2fs_get_mem(fs->blocksize, buf);
3451 err = ext2fs_bmap2(fs, ino, (struct ext2_inode *)inode, *buf, 0,
3452 offset / fs->blocksize, &retflags, &blk);
3456 err = io_channel_read_blk(fs->io, blk, 1, *buf);
3459 if (!blk || (retflags & BMAP_RET_UNINIT))
3463 memset(*buf, 0, residue);
3465 memset(*buf + residue, 0, fs->blocksize - residue);
3467 return io_channel_write_blk(fs->io, blk, 1, *buf);
3470 static int punch_helper(struct fuse_file_info *fp, int mode, off_t offset,
3473 struct fuse_context *ctxt = fuse_get_context();
3474 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3475 struct fuse2fs_file_handle *fh =
3476 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
3478 struct ext2_inode_large inode;
3483 FUSE2FS_CHECK_CONTEXT(ff);
3485 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3486 dbg_printf("%s: offset=%jd len=%jd\n", __func__, offset, len);
3488 /* kernel ext4 punch requires this flag to be set */
3489 if (!(mode & FL_KEEP_SIZE_FLAG))
3492 /* Punch out a bunch of blocks */
3493 start = (offset + fs->blocksize - 1) / fs->blocksize;
3494 end = (offset + len - fs->blocksize) / fs->blocksize;
3495 dbg_printf("%s: ino=%d mode=0x%x start=%llu end=%llu\n", __func__,
3496 fh->ino, mode, start, end);
3498 memset(&inode, 0, sizeof(inode));
3499 err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3502 return translate_error(fs, fh->ino, err);
3504 /* Zero everything before the first block and after the last block */
3505 if ((offset / fs->blocksize) == ((offset + len) / fs->blocksize))
3506 err = clean_block_middle(fs, fh->ino, &inode, offset,
3509 err = clean_block_edge(fs, fh->ino, &inode, offset, 0, &buf);
3511 err = clean_block_edge(fs, fh->ino, &inode,
3512 offset + len, 1, &buf);
3515 ext2fs_free_mem(&buf);
3517 return translate_error(fs, fh->ino, err);
3519 /* Unmap full blocks in the middle */
3521 err = ext2fs_punch(fs, fh->ino, (struct ext2_inode *)&inode,
3524 return translate_error(fs, fh->ino, err);
3527 err = update_mtime(fs, fh->ino, &inode);
3531 err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3534 return translate_error(fs, fh->ino, err);
3539 static int op_fallocate(const char *path EXT2FS_ATTR((unused)), int mode,
3540 off_t offset, off_t len,
3541 struct fuse_file_info *fp)
3543 struct fuse_context *ctxt = fuse_get_context();
3544 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3545 ext2_filsys fs = ff->fs;
3548 /* Catch unknown flags */
3549 if (mode & ~(FL_PUNCH_HOLE_FLAG | FL_KEEP_SIZE_FLAG))
3552 pthread_mutex_lock(&ff->bfl);
3553 if (!fs_writeable(fs)) {
3557 if (mode & FL_PUNCH_HOLE_FLAG)
3558 ret = punch_helper(fp, mode, offset, len);
3560 ret = fallocate_helper(fp, mode, offset, len);
3562 pthread_mutex_unlock(&ff->bfl);
3566 # endif /* SUPPORT_FALLOCATE */
3567 #endif /* FUSE 29 */
3569 static struct fuse_operations fs_ops = {
3571 .destroy = op_destroy,
3572 .getattr = op_getattr,
3573 .readlink = op_readlink,
3576 .unlink = op_unlink,
3578 .symlink = op_symlink,
3579 .rename = op_rename,
3583 .truncate = op_truncate,
3587 .statfs = op_statfs,
3588 .release = op_release,
3590 .setxattr = op_setxattr,
3591 .getxattr = op_getxattr,
3592 .listxattr = op_listxattr,
3593 .removexattr = op_removexattr,
3595 .readdir = op_readdir,
3596 .releasedir = op_release,
3597 .fsyncdir = op_fsync,
3598 .access = op_access,
3599 .create = op_create,
3600 .ftruncate = op_ftruncate,
3601 .fgetattr = op_fgetattr,
3602 .utimens = op_utimens,
3603 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
3604 # if defined(UTIME_NOW) || defined(UTIME_OMIT)
3605 .flag_utime_omit_ok = 1,
3613 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
3615 .flag_nullpath_ok = 1,
3617 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
3619 # ifdef SUPPORT_FALLOCATE
3620 .fallocate = op_fallocate,
3625 static int get_random_bytes(void *p, size_t sz)
3630 fd = open("/dev/urandom", O_RDONLY);
3632 perror("/dev/urandom");
3636 r = read(fd, p, sz);
3639 return (size_t) r == sz;
3648 #define FUSE2FS_OPT(t, p, v) { t, offsetof(struct fuse2fs, p), v }
3650 static struct fuse_opt fuse2fs_opts[] = {
3651 FUSE2FS_OPT("ro", ro, 1),
3652 FUSE2FS_OPT("errors=panic", panic_on_error, 1),
3653 FUSE2FS_OPT("minixdf", minixdf, 1),
3654 FUSE2FS_OPT("fuse2fs_debug", debug, 1),
3655 FUSE2FS_OPT("no_default_opts", no_default_opts, 1),
3657 FUSE_OPT_KEY("-V", FUSE2FS_VERSION),
3658 FUSE_OPT_KEY("--version", FUSE2FS_VERSION),
3659 FUSE_OPT_KEY("-h", FUSE2FS_HELP),
3660 FUSE_OPT_KEY("--help", FUSE2FS_HELP),
3661 FUSE_OPT_KEY("--helpfull", FUSE2FS_HELPFULL),
3666 static int fuse2fs_opt_proc(void *data, const char *arg,
3667 int key, struct fuse_args *outargs)
3669 struct fuse2fs *ff = data;
3672 case FUSE_OPT_KEY_NONOPT:
3674 ff->device = strdup(arg);
3679 case FUSE2FS_HELPFULL:
3681 "usage: %s device/image mountpoint [options]\n"
3683 "general options:\n"
3684 " -o opt,[opt...] mount options\n"
3685 " -h --help print help\n"
3686 " -V --version print version\n"
3688 "fuse2fs options:\n"
3689 " -o ro read-only mount\n"
3690 " -o errors=panic dump core on error\n"
3691 " -o minixdf minix-style df\n"
3692 " -o no_default_opts do not include default fuse options\n"
3693 " -o fuse2fs_debug enable fuse2fs debugging\n"
3696 if (key == FUSE2FS_HELPFULL) {
3697 fuse_opt_add_arg(outargs, "-ho");
3698 fuse_main(outargs->argc, outargs->argv, &fs_ops, NULL);
3700 fprintf(stderr, "Try --helpfull to get a list of "
3701 "all flags, including the FUSE options.\n");
3705 case FUSE2FS_VERSION:
3706 fprintf(stderr, "fuse2fs %s (%s)\n", E2FSPROGS_VERSION,
3708 fuse_opt_add_arg(outargs, "--version");
3709 fuse_main(outargs->argc, outargs->argv, &fs_ops, NULL);
3715 int main(int argc, char *argv[])
3717 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
3718 struct fuse2fs fctx;
3721 char extra_args[BUFSIZ];
3722 int ret = 0, flags = EXT2_FLAG_64BITS | EXT2_FLAG_EXCLUSIVE;
3724 memset(&fctx, 0, sizeof(fctx));
3725 fctx.magic = FUSE2FS_MAGIC;
3727 fuse_opt_parse(&args, &fctx, fuse2fs_opts, fuse2fs_opt_proc);
3728 if (fctx.device == NULL) {
3729 fprintf(stderr, "Missing ext4 device/image\n");
3730 fprintf(stderr, "See '%s -h' for usage\n", argv[0]);
3735 printf("%s", _("Mounting read-only.\n"));
3738 setlocale(LC_MESSAGES, "");
3739 setlocale(LC_CTYPE, "");
3740 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
3741 textdomain(NLS_CAT_NAME);
3742 set_com_err_gettext(gettext);
3744 add_error_table(&et_ext2_error_table);
3746 /* Set up error logging */
3747 logfile = getenv("FUSE2FS_LOGFILE");
3749 fctx.err_fp = fopen(logfile, "a");
3755 fctx.err_fp = stderr;
3757 /* Will we allow users to allocate every last block? */
3758 if (getenv("FUSE2FS_ALLOC_ALL_BLOCKS")) {
3759 printf(_("%s: Allowing users to allocate all blocks. "
3760 "This is dangerous!\n"), fctx.device);
3761 fctx.alloc_all_blocks = 1;
3764 /* Start up the fs (while we still can use stdout) */
3767 flags |= EXT2_FLAG_RW;
3768 err = ext2fs_open2(fctx.device, NULL, flags, 0, 0, unix_io_manager,
3771 printf(_("%s: %s.\n"), fctx.device, error_message(err));
3772 printf(_("Please run e2fsck -fy %s.\n"), fctx.device);
3775 fctx.fs = global_fs;
3776 global_fs->priv_data = &fctx;
3780 if (ext2fs_has_feature_journal_needs_recovery(global_fs->super)) {
3782 printf(_("%s: recovering journal\n"), fctx.device);
3783 err = ext2fs_run_ext3_journal(&global_fs);
3785 printf(_("%s: %s.\n"), fctx.device,
3786 error_message(err));
3787 printf(_("Please run e2fsck -fy %s.\n"),
3791 ext2fs_clear_feature_journal_needs_recovery(global_fs->super);
3792 ext2fs_mark_super_dirty(global_fs);
3794 printf("%s", _("Journal needs recovery; running "
3795 "`e2fsck -E journal_only' is required.\n"));
3801 if (ext2fs_has_feature_journal(global_fs->super))
3802 printf(_("%s: Writing to the journal is not supported.\n"),
3804 err = ext2fs_read_inode_bitmap(global_fs);
3806 translate_error(global_fs, 0, err);
3809 err = ext2fs_read_block_bitmap(global_fs);
3811 translate_error(global_fs, 0, err);
3816 if (!(global_fs->super->s_state & EXT2_VALID_FS))
3817 printf("%s", _("Warning: Mounting unchecked fs, running e2fsck "
3818 "is recommended.\n"));
3819 if (global_fs->super->s_max_mnt_count > 0 &&
3820 global_fs->super->s_mnt_count >= global_fs->super->s_max_mnt_count)
3821 printf("%s", _("Warning: Maximal mount count reached, running "
3822 "e2fsck is recommended.\n"));
3823 if (global_fs->super->s_checkinterval > 0 &&
3824 (time_t) (global_fs->super->s_lastcheck +
3825 global_fs->super->s_checkinterval) <= time(0))
3826 printf("%s", _("Warning: Check time reached; running e2fsck "
3827 "is recommended.\n"));
3828 if (global_fs->super->s_last_orphan)
3830 _("Orphans detected; running e2fsck is recommended.\n"));
3832 if (global_fs->super->s_state & EXT2_ERROR_FS) {
3834 _("Errors detected; running e2fsck is required.\n"));
3838 /* Initialize generation counter */
3839 get_random_bytes(&fctx.next_generation, sizeof(unsigned int));
3841 /* Set up default fuse parameters */
3842 snprintf(extra_args, BUFSIZ, "-okernel_cache,subtype=ext4,use_ino,"
3843 "fsname=%s,attr_timeout=0" FUSE_PLATFORM_OPTS,
3845 if (fctx.no_default_opts == 0)
3846 fuse_opt_add_arg(&args, extra_args);
3851 printf("fuse arguments:");
3852 for (i = 0; i < args.argc; i++)
3853 printf(" '%s'", args.argv[i]);
3857 pthread_mutex_init(&fctx.bfl, NULL);
3858 fuse_main(args.argc, args.argv, &fs_ops, &fctx);
3859 pthread_mutex_destroy(&fctx.bfl);
3864 err = ext2fs_close(global_fs);
3866 com_err(argv[0], err, "while closing fs");
3872 static int __translate_error(ext2_filsys fs, errcode_t err, ext2_ino_t ino,
3873 const char *file, int line)
3875 struct timespec now;
3877 struct fuse2fs *ff = fs->priv_data;
3880 /* Translate ext2 error to unix error code */
3881 if (err < EXT2_ET_BASE)
3882 goto no_translation;
3884 case EXT2_ET_NO_MEMORY:
3885 case EXT2_ET_TDB_ERR_OOM:
3888 case EXT2_ET_INVALID_ARGUMENT:
3889 case EXT2_ET_LLSEEK_FAILED:
3892 case EXT2_ET_NO_DIRECTORY:
3895 case EXT2_ET_FILE_NOT_FOUND:
3898 case EXT2_ET_DIR_NO_SPACE:
3901 case EXT2_ET_TOOSMALL:
3902 case EXT2_ET_BLOCK_ALLOC_FAIL:
3903 case EXT2_ET_INODE_ALLOC_FAIL:
3904 case EXT2_ET_EA_NO_SPACE:
3907 case EXT2_ET_SYMLINK_LOOP:
3910 case EXT2_ET_FILE_TOO_BIG:
3913 case EXT2_ET_TDB_ERR_EXISTS:
3914 case EXT2_ET_FILE_EXISTS:
3917 case EXT2_ET_MMP_FAILED:
3918 case EXT2_ET_MMP_FSCK_ON:
3921 case EXT2_ET_EA_KEY_NOT_FOUND:
3928 /* Sometimes fuse returns a garbage file handle pointer to us... */
3929 case EXT2_ET_MAGIC_EXT2_FILE:
3932 case EXT2_ET_UNIMPLEMENTED:
3946 fprintf(ff->err_fp, "FUSE2FS (%s): %s (inode #%d) at %s:%d.\n",
3947 fs->device_name ? fs->device_name : "???",
3948 error_message(err), ino, file, line);
3950 fprintf(ff->err_fp, "FUSE2FS (%s): %s at %s:%d.\n",
3951 fs->device_name ? fs->device_name : "???",
3952 error_message(err), file, line);
3955 /* Make a note in the error log */
3957 fs->super->s_last_error_time = now.tv_sec;
3958 fs->super->s_last_error_ino = ino;
3959 fs->super->s_last_error_line = line;
3960 fs->super->s_last_error_block = err; /* Yeah... */
3961 strncpy((char *)fs->super->s_last_error_func, file,
3962 sizeof(fs->super->s_last_error_func));
3963 if (fs->super->s_first_error_time == 0) {
3964 fs->super->s_first_error_time = now.tv_sec;
3965 fs->super->s_first_error_ino = ino;
3966 fs->super->s_first_error_line = line;
3967 fs->super->s_first_error_block = err;
3968 strncpy((char *)fs->super->s_first_error_func, file,
3969 sizeof(fs->super->s_first_error_func));
3972 fs->super->s_error_count++;
3973 ext2fs_mark_super_dirty(fs);
3975 if (ff->panic_on_error)