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 acl_ea_entry a_entries[0];
124 static inline size_t acl_ea_size(int count)
126 return sizeof(acl_ea_header) + count * sizeof(acl_ea_entry);
129 static inline int acl_ea_count(size_t size)
131 if (size < sizeof(acl_ea_header))
133 size -= sizeof(acl_ea_header);
134 if (size % sizeof(acl_ea_entry))
136 return size / sizeof(acl_ea_entry);
140 * ext4 ACL structures, copied from fs/ext4/acl.h.
142 #define EXT4_ACL_VERSION 0x0001
153 } ext4_acl_entry_short;
159 static inline size_t ext4_acl_size(int count)
162 return sizeof(ext4_acl_header) +
163 count * sizeof(ext4_acl_entry_short);
165 return sizeof(ext4_acl_header) +
166 4 * sizeof(ext4_acl_entry_short) +
167 (count - 4) * sizeof(ext4_acl_entry);
171 static inline int ext4_acl_count(size_t size)
175 size -= sizeof(ext4_acl_header);
176 s = size - 4 * sizeof(ext4_acl_entry_short);
178 if (size % sizeof(ext4_acl_entry_short))
180 return size / sizeof(ext4_acl_entry_short);
182 if (s % sizeof(ext4_acl_entry))
184 return s / sizeof(ext4_acl_entry) + 4;
187 static errcode_t fuse_to_ext4_acl(acl_ea_header *facl, size_t facl_sz,
188 ext4_acl_header **eacl, size_t *eacl_sz)
198 facl_count = acl_ea_count(facl_sz);
199 h_sz = ext4_acl_size(facl_count);
200 if (facl_count < 0 || facl->a_version != ACL_EA_VERSION)
201 return EXT2_ET_INVALID_ARGUMENT;
203 err = ext2fs_get_mem(h_sz, &h);
207 h->a_version = ext2fs_cpu_to_le32(EXT4_ACL_VERSION);
208 hptr = (unsigned char *) (h + 1);
209 for (i = 0, a = facl->a_entries; i < facl_count; i++, a++) {
210 e = (ext4_acl_entry *) hptr;
211 e->e_tag = ext2fs_cpu_to_le16(a->e_tag);
212 e->e_perm = ext2fs_cpu_to_le16(a->e_perm);
217 e->e_id = ext2fs_cpu_to_le32(a->e_id);
218 hptr += sizeof(ext4_acl_entry);
224 hptr += sizeof(ext4_acl_entry_short);
227 err = EXT2_ET_INVALID_ARGUMENT;
240 static errcode_t ext4_to_fuse_acl(acl_ea_header **facl, size_t *facl_sz,
241 ext4_acl_header *eacl, size_t eacl_sz)
251 eacl_count = ext4_acl_count(eacl_sz);
252 f_sz = acl_ea_size(eacl_count);
253 if (eacl_count < 0 ||
254 eacl->a_version != ext2fs_cpu_to_le32(EXT4_ACL_VERSION))
255 return EXT2_ET_INVALID_ARGUMENT;
257 err = ext2fs_get_mem(f_sz, &f);
261 f->a_version = ACL_EA_VERSION;
262 hptr = (unsigned char *) (eacl + 1);
263 for (i = 0, a = f->a_entries; i < eacl_count; i++, a++) {
264 e = (ext4_acl_entry *) hptr;
265 a->e_tag = ext2fs_le16_to_cpu(e->e_tag);
266 a->e_perm = ext2fs_le16_to_cpu(e->e_perm);
271 a->e_id = ext2fs_le32_to_cpu(e->e_id);
272 hptr += sizeof(ext4_acl_entry);
278 hptr += sizeof(ext4_acl_entry_short);
281 err = EXT2_ET_INVALID_ARGUMENT;
293 #endif /* TRANSLATE_LINUX_ACLS */
296 * ext2_file_t contains a struct inode, so we can't leave files open.
297 * Use this as a proxy instead.
299 #define FUSE2FS_FILE_MAGIC (0xEF53DEAFUL)
300 struct fuse2fs_file_handle {
306 /* Main program context */
307 #define FUSE2FS_MAGIC (0xEF53DEADUL)
318 int alloc_all_blocks;
320 unsigned int next_generation;
323 #define FUSE2FS_CHECK_MAGIC(fs, ptr, num) do {if ((ptr)->magic != (num)) \
324 return translate_error((fs), 0, EXT2_ET_MAGIC_EXT2_FILE); \
327 #define FUSE2FS_CHECK_CONTEXT(ptr) do {if ((ptr)->magic != FUSE2FS_MAGIC) \
328 return translate_error(global_fs, 0, EXT2_ET_BAD_MAGIC); \
331 static int __translate_error(ext2_filsys fs, errcode_t err, ext2_ino_t ino,
332 const char *file, int line);
333 #define translate_error(fs, ino, err) __translate_error((fs), (err), (ino), \
345 #define EXT4_EPOCH_BITS 2
346 #define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1)
347 #define EXT4_NSEC_MASK (~0UL << EXT4_EPOCH_BITS)
350 * Extended fields will fit into an inode if the filesystem was formatted
351 * with large inodes (-I 256 or larger) and there are not currently any EAs
352 * consuming all of the available space. For new inodes we always reserve
353 * enough space for the kernel's known extended fields, but for inodes
354 * created with an old kernel this might not have been the case. None of
355 * the extended inode fields is critical for correct filesystem operation.
356 * This macro checks if a certain field fits in the inode. Note that
357 * inode-size = GOOD_OLD_INODE_SIZE + i_extra_isize
359 #define EXT4_FITS_IN_INODE(ext4_inode, field) \
360 ((offsetof(typeof(*ext4_inode), field) + \
361 sizeof((ext4_inode)->field)) \
362 <= ((size_t) EXT2_GOOD_OLD_INODE_SIZE + \
363 (ext4_inode)->i_extra_isize)) \
365 static inline __u32 ext4_encode_extra_time(const struct timespec *time)
367 __u32 extra = sizeof(time->tv_sec) > 4 ?
368 ((time->tv_sec - (__s32)time->tv_sec) >> 32) &
370 return extra | (time->tv_nsec << EXT4_EPOCH_BITS);
373 static inline void ext4_decode_extra_time(struct timespec *time, __u32 extra)
375 if (sizeof(time->tv_sec) > 4 && (extra & EXT4_EPOCH_MASK)) {
376 __u64 extra_bits = extra & EXT4_EPOCH_MASK;
378 * Prior to kernel 3.14?, we had a broken decode function,
379 * wherein we effectively did this:
380 * if (extra_bits == 3)
383 time->tv_sec += extra_bits << 32;
385 time->tv_nsec = ((extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
388 #define EXT4_INODE_SET_XTIME(xtime, timespec, raw_inode) \
390 (raw_inode)->xtime = (timespec)->tv_sec; \
391 if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \
392 (raw_inode)->xtime ## _extra = \
393 ext4_encode_extra_time(timespec); \
396 #define EXT4_EINODE_SET_XTIME(xtime, timespec, raw_inode) \
398 if (EXT4_FITS_IN_INODE(raw_inode, xtime)) \
399 (raw_inode)->xtime = (timespec)->tv_sec; \
400 if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \
401 (raw_inode)->xtime ## _extra = \
402 ext4_encode_extra_time(timespec); \
405 #define EXT4_INODE_GET_XTIME(xtime, timespec, raw_inode) \
407 (timespec)->tv_sec = (signed)((raw_inode)->xtime); \
408 if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \
409 ext4_decode_extra_time((timespec), \
410 (raw_inode)->xtime ## _extra); \
412 (timespec)->tv_nsec = 0; \
415 #define EXT4_EINODE_GET_XTIME(xtime, timespec, raw_inode) \
417 if (EXT4_FITS_IN_INODE(raw_inode, xtime)) \
418 (timespec)->tv_sec = \
419 (signed)((raw_inode)->xtime); \
420 if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \
421 ext4_decode_extra_time((timespec), \
422 raw_inode->xtime ## _extra); \
424 (timespec)->tv_nsec = 0; \
427 static void get_now(struct timespec *now)
429 #ifdef CLOCK_REALTIME
430 if (!clock_gettime(CLOCK_REALTIME, now))
434 now->tv_sec = time(NULL);
438 static void increment_version(struct ext2_inode_large *inode)
442 ver = inode->osd1.linux1.l_i_version;
443 if (EXT4_FITS_IN_INODE(inode, i_version_hi))
444 ver |= (__u64)inode->i_version_hi << 32;
446 inode->osd1.linux1.l_i_version = ver;
447 if (EXT4_FITS_IN_INODE(inode, i_version_hi))
448 inode->i_version_hi = ver >> 32;
451 static void init_times(struct ext2_inode_large *inode)
456 EXT4_INODE_SET_XTIME(i_atime, &now, inode);
457 EXT4_INODE_SET_XTIME(i_ctime, &now, inode);
458 EXT4_INODE_SET_XTIME(i_mtime, &now, inode);
459 EXT4_EINODE_SET_XTIME(i_crtime, &now, inode);
460 increment_version(inode);
463 static int update_ctime(ext2_filsys fs, ext2_ino_t ino,
464 struct ext2_inode_large *pinode)
468 struct ext2_inode_large inode;
472 /* If user already has a inode buffer, just update that */
474 increment_version(pinode);
475 EXT4_INODE_SET_XTIME(i_ctime, &now, pinode);
479 /* Otherwise we have to read-modify-write the inode */
480 memset(&inode, 0, sizeof(inode));
481 err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
484 return translate_error(fs, ino, err);
486 increment_version(&inode);
487 EXT4_INODE_SET_XTIME(i_ctime, &now, &inode);
489 err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
492 return translate_error(fs, ino, err);
497 static int update_atime(ext2_filsys fs, ext2_ino_t ino)
500 struct ext2_inode_large inode, *pinode;
501 struct timespec atime, mtime, now;
503 if (!(fs->flags & EXT2_FLAG_RW))
505 memset(&inode, 0, sizeof(inode));
506 err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
509 return translate_error(fs, ino, err);
512 EXT4_INODE_GET_XTIME(i_atime, &atime, pinode);
513 EXT4_INODE_GET_XTIME(i_mtime, &mtime, pinode);
516 * If atime is newer than mtime and atime hasn't been updated in thirty
517 * seconds, skip the atime update. Same idea as Linux "relatime".
519 if (atime.tv_sec >= mtime.tv_sec && atime.tv_sec >= now.tv_sec - 30)
521 EXT4_INODE_SET_XTIME(i_atime, &now, &inode);
523 err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
526 return translate_error(fs, ino, err);
531 static int update_mtime(ext2_filsys fs, ext2_ino_t ino,
532 struct ext2_inode_large *pinode)
535 struct ext2_inode_large inode;
540 EXT4_INODE_SET_XTIME(i_mtime, &now, pinode);
541 EXT4_INODE_SET_XTIME(i_ctime, &now, pinode);
542 increment_version(pinode);
546 memset(&inode, 0, sizeof(inode));
547 err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
550 return translate_error(fs, ino, err);
553 EXT4_INODE_SET_XTIME(i_mtime, &now, &inode);
554 EXT4_INODE_SET_XTIME(i_ctime, &now, &inode);
555 increment_version(&inode);
557 err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
560 return translate_error(fs, ino, err);
565 static int ext2_file_type(unsigned int mode)
567 if (LINUX_S_ISREG(mode))
568 return EXT2_FT_REG_FILE;
570 if (LINUX_S_ISDIR(mode))
573 if (LINUX_S_ISCHR(mode))
574 return EXT2_FT_CHRDEV;
576 if (LINUX_S_ISBLK(mode))
577 return EXT2_FT_BLKDEV;
579 if (LINUX_S_ISLNK(mode))
580 return EXT2_FT_SYMLINK;
582 if (LINUX_S_ISFIFO(mode))
585 if (LINUX_S_ISSOCK(mode))
591 static int fs_can_allocate(struct fuse2fs *ff, blk64_t num)
593 ext2_filsys fs = ff->fs;
596 dbg_printf("%s: Asking for %llu; alloc_all=%d total=%llu free=%llu "
597 "rsvd=%llu\n", __func__, num, ff->alloc_all_blocks,
598 ext2fs_blocks_count(fs->super),
599 ext2fs_free_blocks_count(fs->super),
600 ext2fs_r_blocks_count(fs->super));
601 if (num > ext2fs_blocks_count(fs->super))
604 if (ff->alloc_all_blocks)
608 * Different meaning for r_blocks -- libext2fs has bugs where the FS
609 * can get corrupted if it totally runs out of blocks. Avoid this
610 * by refusing to allocate any of the reserve blocks to anybody.
612 reserved = ext2fs_r_blocks_count(fs->super);
614 reserved = ext2fs_blocks_count(fs->super) / 10;
615 return ext2fs_free_blocks_count(fs->super) > reserved + num;
618 static int fs_writeable(ext2_filsys fs)
620 return (fs->flags & EXT2_FLAG_RW) && (fs->super->s_error_count == 0);
623 static int check_inum_access(ext2_filsys fs, ext2_ino_t ino, mode_t mask)
625 struct fuse_context *ctxt = fuse_get_context();
626 struct ext2_inode inode;
630 /* no writing to read-only or broken fs */
631 if ((mask & W_OK) && !fs_writeable(fs))
634 err = ext2fs_read_inode(fs, ino, &inode);
636 return translate_error(fs, ino, err);
637 perms = inode.i_mode & 0777;
639 dbg_printf("access ino=%d mask=e%s%s%s perms=0%o fuid=%d fgid=%d "
640 "uid=%d gid=%d\n", ino,
641 (mask & R_OK ? "r" : ""), (mask & W_OK ? "w" : ""),
642 (mask & X_OK ? "x" : ""), perms, inode.i_uid, inode.i_gid,
643 ctxt->uid, ctxt->gid);
645 /* existence check */
651 (inode.i_flags & EXT2_IMMUTABLE_FL))
654 /* Figure out what root's allowed to do */
655 if (ctxt->uid == 0) {
656 /* Non-file access always ok */
657 if (!LINUX_S_ISREG(inode.i_mode))
660 /* R/W access to a file always ok */
664 /* X access to a file ok if a user/group/other can X */
668 /* Trying to execute a file that's not executable. BZZT! */
672 /* allow owner, if perms match */
673 if (inode.i_uid == ctxt->uid) {
674 if ((mask & (perms >> 6)) == mask)
679 /* allow group, if perms match */
680 if (inode.i_gid == ctxt->gid) {
681 if ((mask & (perms >> 3)) == mask)
686 /* otherwise check other */
687 if ((mask & perms) == mask)
692 static void op_destroy(void *p EXT2FS_ATTR((unused)))
694 struct fuse_context *ctxt = fuse_get_context();
695 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
699 if (ff->magic != FUSE2FS_MAGIC) {
700 translate_error(global_fs, 0, EXT2_ET_BAD_MAGIC);
704 dbg_printf("%s: dev=%s\n", __func__, fs->device_name);
705 if (fs->flags & EXT2_FLAG_RW) {
706 fs->super->s_state |= EXT2_VALID_FS;
707 if (fs->super->s_error_count)
708 fs->super->s_state |= EXT2_ERROR_FS;
709 ext2fs_mark_super_dirty(fs);
710 err = ext2fs_set_gdt_csum(fs);
712 translate_error(fs, 0, err);
714 err = ext2fs_flush2(fs, 0);
716 translate_error(fs, 0, err);
720 static void *op_init(struct fuse_conn_info *conn)
722 struct fuse_context *ctxt = fuse_get_context();
723 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
727 if (ff->magic != FUSE2FS_MAGIC) {
728 translate_error(global_fs, 0, EXT2_ET_BAD_MAGIC);
732 dbg_printf("%s: dev=%s\n", __func__, fs->device_name);
733 #ifdef FUSE_CAP_IOCTL_DIR
734 conn->want |= FUSE_CAP_IOCTL_DIR;
736 if (fs->flags & EXT2_FLAG_RW) {
737 fs->super->s_mnt_count++;
738 fs->super->s_mtime = time(NULL);
739 fs->super->s_state &= ~EXT2_VALID_FS;
740 ext2fs_mark_super_dirty(fs);
741 err = ext2fs_flush2(fs, 0);
743 translate_error(fs, 0, err);
748 static blkcnt_t blocks_from_inode(ext2_filsys fs,
749 struct ext2_inode_large *inode)
754 if (ext2fs_has_feature_huge_file(fs->super))
755 b += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32;
757 if (!ext2fs_has_feature_huge_file(fs->super) ||
758 !(inode->i_flags & EXT4_HUGE_FILE_FL))
759 b *= fs->blocksize / 512;
760 b *= EXT2FS_CLUSTER_RATIO(fs);
765 static int stat_inode(ext2_filsys fs, ext2_ino_t ino, struct stat *statbuf)
767 struct ext2_inode_large inode;
773 memset(&inode, 0, sizeof(inode));
774 err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
777 return translate_error(fs, ino, err);
779 memcpy(&fakedev, fs->super->s_uuid, sizeof(fakedev));
780 statbuf->st_dev = fakedev;
781 statbuf->st_ino = ino;
782 statbuf->st_mode = inode.i_mode;
783 statbuf->st_nlink = inode.i_links_count;
784 statbuf->st_uid = inode.i_uid;
785 statbuf->st_gid = inode.i_gid;
786 statbuf->st_size = EXT2_I_SIZE(&inode);
787 statbuf->st_blksize = fs->blocksize;
788 statbuf->st_blocks = blocks_from_inode(fs, &inode);
789 EXT4_INODE_GET_XTIME(i_atime, &tv, &inode);
790 statbuf->st_atime = tv.tv_sec;
791 EXT4_INODE_GET_XTIME(i_mtime, &tv, &inode);
792 statbuf->st_mtime = tv.tv_sec;
793 EXT4_INODE_GET_XTIME(i_ctime, &tv, &inode);
794 statbuf->st_ctime = tv.tv_sec;
795 if (LINUX_S_ISCHR(inode.i_mode) ||
796 LINUX_S_ISBLK(inode.i_mode)) {
797 if (inode.i_block[0])
798 statbuf->st_rdev = inode.i_block[0];
800 statbuf->st_rdev = inode.i_block[1];
806 static int op_getattr(const char *path, struct stat *statbuf)
808 struct fuse_context *ctxt = fuse_get_context();
809 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
815 FUSE2FS_CHECK_CONTEXT(ff);
817 dbg_printf("%s: path=%s\n", __func__, path);
818 pthread_mutex_lock(&ff->bfl);
819 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
821 ret = translate_error(fs, 0, err);
824 ret = stat_inode(fs, ino, statbuf);
826 pthread_mutex_unlock(&ff->bfl);
830 static int op_readlink(const char *path, char *buf, size_t len)
832 struct fuse_context *ctxt = fuse_get_context();
833 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
837 struct ext2_inode inode;
842 FUSE2FS_CHECK_CONTEXT(ff);
844 dbg_printf("%s: path=%s\n", __func__, path);
845 pthread_mutex_lock(&ff->bfl);
846 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
847 if (err || ino == 0) {
848 ret = translate_error(fs, 0, err);
852 err = ext2fs_read_inode(fs, ino, &inode);
854 ret = translate_error(fs, ino, err);
858 if (!LINUX_S_ISLNK(inode.i_mode)) {
864 if (inode.i_size < len)
866 if (ext2fs_inode_data_blocks2(fs, &inode) ||
867 (inode.i_flags & EXT4_INLINE_DATA_FL)) {
868 /* big/inline symlink */
870 err = ext2fs_file_open(fs, ino, 0, &file);
872 ret = translate_error(fs, ino, err);
876 err = ext2fs_file_read(file, buf, len, &got);
877 if (err || got != len) {
878 ext2fs_file_close(file);
879 ret = translate_error(fs, ino, err);
884 err = ext2fs_file_close(file);
888 ret = translate_error(fs, ino, err);
893 memcpy(buf, (char *)inode.i_block, len);
896 if (fs_writeable(fs)) {
897 ret = update_atime(fs, ino);
903 pthread_mutex_unlock(&ff->bfl);
907 static int op_mknod(const char *path, mode_t mode, dev_t dev)
909 struct fuse_context *ctxt = fuse_get_context();
910 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
912 ext2_ino_t parent, child;
917 struct ext2_inode_large inode;
920 FUSE2FS_CHECK_CONTEXT(ff);
922 dbg_printf("%s: path=%s mode=0%o dev=0x%x\n", __func__, path, mode,
924 temp_path = strdup(path);
929 node_name = strrchr(temp_path, '/');
938 pthread_mutex_lock(&ff->bfl);
939 if (!fs_can_allocate(ff, 2)) {
944 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
947 ret = translate_error(fs, 0, err);
951 ret = check_inum_access(fs, parent, W_OK);
957 if (LINUX_S_ISCHR(mode))
958 filetype = EXT2_FT_CHRDEV;
959 else if (LINUX_S_ISBLK(mode))
960 filetype = EXT2_FT_BLKDEV;
961 else if (LINUX_S_ISFIFO(mode))
962 filetype = EXT2_FT_FIFO;
963 else if (LINUX_S_ISSOCK(mode))
964 filetype = EXT2_FT_SOCK;
970 err = ext2fs_new_inode(fs, parent, mode, 0, &child);
972 ret = translate_error(fs, 0, err);
976 dbg_printf("%s: create ino=%d/name=%s in dir=%d\n", __func__, child,
978 err = ext2fs_link(fs, parent, node_name, child, filetype);
979 if (err == EXT2_ET_DIR_NO_SPACE) {
980 err = ext2fs_expand_dir(fs, parent);
982 ret = translate_error(fs, parent, err);
986 err = ext2fs_link(fs, parent, node_name, child,
990 ret = translate_error(fs, parent, err);
994 ret = update_mtime(fs, parent, NULL);
998 memset(&inode, 0, sizeof(inode));
1002 inode.i_block[1] = dev;
1004 inode.i_block[0] = dev;
1005 inode.i_links_count = 1;
1006 inode.i_extra_isize = sizeof(struct ext2_inode_large) -
1007 EXT2_GOOD_OLD_INODE_SIZE;
1008 inode.i_uid = ctxt->uid;
1009 inode.i_gid = ctxt->gid;
1011 err = ext2fs_write_new_inode(fs, child, (struct ext2_inode *)&inode);
1013 ret = translate_error(fs, child, err);
1017 inode.i_generation = ff->next_generation++;
1019 err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode,
1022 ret = translate_error(fs, child, err);
1026 ext2fs_inode_alloc_stats2(fs, child, 1, 0);
1029 pthread_mutex_unlock(&ff->bfl);
1035 static int op_mkdir(const char *path, mode_t mode)
1037 struct fuse_context *ctxt = fuse_get_context();
1038 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1040 ext2_ino_t parent, child;
1044 struct ext2_inode_large inode;
1050 FUSE2FS_CHECK_CONTEXT(ff);
1052 dbg_printf("%s: path=%s mode=0%o\n", __func__, path, mode);
1053 temp_path = strdup(path);
1058 node_name = strrchr(temp_path, '/');
1067 pthread_mutex_lock(&ff->bfl);
1068 if (!fs_can_allocate(ff, 1)) {
1073 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
1076 ret = translate_error(fs, 0, err);
1080 ret = check_inum_access(fs, parent, W_OK);
1084 /* Is the parent dir sgid? */
1085 err = ext2fs_read_inode_full(fs, parent, (struct ext2_inode *)&inode,
1088 ret = translate_error(fs, parent, err);
1091 parent_sgid = inode.i_mode & S_ISGID;
1095 err = ext2fs_mkdir(fs, parent, 0, node_name);
1096 if (err == EXT2_ET_DIR_NO_SPACE) {
1097 err = ext2fs_expand_dir(fs, parent);
1099 ret = translate_error(fs, parent, err);
1103 err = ext2fs_mkdir(fs, parent, 0, node_name);
1106 ret = translate_error(fs, parent, err);
1110 ret = update_mtime(fs, parent, NULL);
1114 /* Still have to update the uid/gid of the dir */
1115 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
1118 ret = translate_error(fs, 0, err);
1121 dbg_printf("%s: created ino=%d/path=%s in dir=%d\n", __func__, child,
1124 memset(&inode, 0, sizeof(inode));
1125 err = ext2fs_read_inode_full(fs, child, (struct ext2_inode *)&inode,
1128 ret = translate_error(fs, child, err);
1132 inode.i_uid = ctxt->uid;
1133 inode.i_gid = ctxt->gid;
1134 inode.i_mode = LINUX_S_IFDIR | (mode & ~(S_ISUID | fs->umask)) |
1136 inode.i_generation = ff->next_generation++;
1138 err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode,
1141 ret = translate_error(fs, child, err);
1145 /* Rewrite the directory block checksum, having set i_generation */
1146 if ((inode.i_flags & EXT4_INLINE_DATA_FL) ||
1147 !ext2fs_has_feature_metadata_csum(fs->super))
1149 err = ext2fs_new_dir_block(fs, child, parent, &block);
1151 ret = translate_error(fs, child, err);
1154 err = ext2fs_bmap2(fs, child, (struct ext2_inode *)&inode, NULL, 0, 0,
1157 ret = translate_error(fs, child, err);
1160 err = ext2fs_write_dir_block4(fs, blk, block, 0, child);
1162 ret = translate_error(fs, child, err);
1167 ext2fs_free_mem(&block);
1169 pthread_mutex_unlock(&ff->bfl);
1175 static int unlink_file_by_name(ext2_filsys fs, const char *path)
1179 char *filename = strdup(path);
1183 base_name = strrchr(filename, '/');
1185 *base_name++ = '\0';
1186 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, filename,
1190 return translate_error(fs, 0, err);
1193 dir = EXT2_ROOT_INO;
1194 base_name = filename;
1197 ret = check_inum_access(fs, dir, W_OK);
1203 dbg_printf("%s: unlinking name=%s from dir=%d\n", __func__,
1205 err = ext2fs_unlink(fs, dir, base_name, 0, 0);
1208 return translate_error(fs, dir, err);
1210 return update_mtime(fs, dir, NULL);
1213 static int remove_inode(struct fuse2fs *ff, ext2_ino_t ino)
1215 ext2_filsys fs = ff->fs;
1217 struct ext2_inode_large inode;
1220 memset(&inode, 0, sizeof(inode));
1221 err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
1224 ret = translate_error(fs, ino, err);
1227 dbg_printf("%s: put ino=%d links=%d\n", __func__, ino,
1228 inode.i_links_count);
1230 switch (inode.i_links_count) {
1232 return 0; /* XXX: already done? */
1234 inode.i_links_count--;
1235 inode.i_dtime = fs->now ? fs->now : time(0);
1238 inode.i_links_count--;
1241 ret = update_ctime(fs, ino, &inode);
1245 if (inode.i_links_count)
1248 /* Nobody holds this file; free its blocks! */
1249 err = ext2fs_free_ext_attr(fs, ino, &inode);
1253 if (ext2fs_inode_has_valid_blocks2(fs, (struct ext2_inode *)&inode)) {
1254 err = ext2fs_punch(fs, ino, (struct ext2_inode *)&inode, NULL,
1257 ret = translate_error(fs, ino, err);
1262 ext2fs_inode_alloc_stats2(fs, ino, -1,
1263 LINUX_S_ISDIR(inode.i_mode));
1266 err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
1269 ret = translate_error(fs, ino, err);
1276 static int __op_unlink(struct fuse2fs *ff, const char *path)
1278 ext2_filsys fs = ff->fs;
1283 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
1285 ret = translate_error(fs, 0, err);
1289 ret = unlink_file_by_name(fs, path);
1293 ret = remove_inode(ff, ino);
1300 static int op_unlink(const char *path)
1302 struct fuse_context *ctxt = fuse_get_context();
1303 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1306 FUSE2FS_CHECK_CONTEXT(ff);
1307 pthread_mutex_lock(&ff->bfl);
1308 ret = __op_unlink(ff, path);
1309 pthread_mutex_unlock(&ff->bfl);
1318 static int rmdir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
1319 int entry EXT2FS_ATTR((unused)),
1320 struct ext2_dir_entry *dirent,
1321 int offset EXT2FS_ATTR((unused)),
1322 int blocksize EXT2FS_ATTR((unused)),
1323 char *buf EXT2FS_ATTR((unused)),
1326 struct rd_struct *rds = (struct rd_struct *) private;
1328 if (dirent->inode == 0)
1330 if (((dirent->name_len & 0xFF) == 1) && (dirent->name[0] == '.'))
1332 if (((dirent->name_len & 0xFF) == 2) && (dirent->name[0] == '.') &&
1333 (dirent->name[1] == '.')) {
1334 rds->parent = dirent->inode;
1341 static int __op_rmdir(struct fuse2fs *ff, const char *path)
1343 ext2_filsys fs = ff->fs;
1346 struct ext2_inode_large inode;
1347 struct rd_struct rds;
1350 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &child);
1352 ret = translate_error(fs, 0, err);
1355 dbg_printf("%s: rmdir path=%s ino=%d\n", __func__, path, child);
1360 err = ext2fs_dir_iterate2(fs, child, 0, 0, rmdir_proc, &rds);
1362 ret = translate_error(fs, child, err);
1366 if (rds.empty == 0) {
1371 ret = unlink_file_by_name(fs, path);
1374 /* Directories have to be "removed" twice. */
1375 ret = remove_inode(ff, child);
1378 ret = remove_inode(ff, child);
1383 dbg_printf("%s: decr dir=%d link count\n", __func__,
1385 err = ext2fs_read_inode_full(fs, rds.parent,
1386 (struct ext2_inode *)&inode,
1389 ret = translate_error(fs, rds.parent, err);
1392 if (inode.i_links_count > 1)
1393 inode.i_links_count--;
1394 ret = update_mtime(fs, rds.parent, &inode);
1397 err = ext2fs_write_inode_full(fs, rds.parent,
1398 (struct ext2_inode *)&inode,
1401 ret = translate_error(fs, rds.parent, err);
1410 static int op_rmdir(const char *path)
1412 struct fuse_context *ctxt = fuse_get_context();
1413 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1416 FUSE2FS_CHECK_CONTEXT(ff);
1417 pthread_mutex_lock(&ff->bfl);
1418 ret = __op_rmdir(ff, path);
1419 pthread_mutex_unlock(&ff->bfl);
1423 static int op_symlink(const char *src, const char *dest)
1425 struct fuse_context *ctxt = fuse_get_context();
1426 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1428 ext2_ino_t parent, child;
1432 struct ext2_inode_large inode;
1435 FUSE2FS_CHECK_CONTEXT(ff);
1437 dbg_printf("%s: symlink %s to %s\n", __func__, src, dest);
1438 temp_path = strdup(dest);
1443 node_name = strrchr(temp_path, '/');
1452 pthread_mutex_lock(&ff->bfl);
1453 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
1457 ret = translate_error(fs, 0, err);
1461 ret = check_inum_access(fs, parent, W_OK);
1466 /* Create symlink */
1467 err = ext2fs_symlink(fs, parent, 0, node_name, src);
1468 if (err == EXT2_ET_DIR_NO_SPACE) {
1469 err = ext2fs_expand_dir(fs, parent);
1471 ret = translate_error(fs, parent, err);
1475 err = ext2fs_symlink(fs, parent, 0, node_name, src);
1478 ret = translate_error(fs, parent, err);
1482 /* Update parent dir's mtime */
1483 ret = update_mtime(fs, parent, NULL);
1487 /* Still have to update the uid/gid of the symlink */
1488 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
1491 ret = translate_error(fs, 0, err);
1494 dbg_printf("%s: symlinking ino=%d/name=%s to dir=%d\n", __func__,
1495 child, node_name, parent);
1497 memset(&inode, 0, sizeof(inode));
1498 err = ext2fs_read_inode_full(fs, child, (struct ext2_inode *)&inode,
1501 ret = translate_error(fs, child, err);
1505 inode.i_uid = ctxt->uid;
1506 inode.i_gid = ctxt->gid;
1507 inode.i_generation = ff->next_generation++;
1509 err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode,
1512 ret = translate_error(fs, child, err);
1516 pthread_mutex_unlock(&ff->bfl);
1522 struct update_dotdot {
1523 ext2_ino_t new_dotdot;
1526 static int update_dotdot_helper(ext2_ino_t dir EXT2FS_ATTR((unused)),
1527 int entry EXT2FS_ATTR((unused)),
1528 struct ext2_dir_entry *dirent,
1529 int offset EXT2FS_ATTR((unused)),
1530 int blocksize EXT2FS_ATTR((unused)),
1531 char *buf EXT2FS_ATTR((unused)),
1534 struct update_dotdot *ud = priv_data;
1536 if (ext2fs_dirent_name_len(dirent) == 2 &&
1537 dirent->name[0] == '.' && dirent->name[1] == '.') {
1538 dirent->inode = ud->new_dotdot;
1539 return DIRENT_CHANGED | DIRENT_ABORT;
1545 static int op_rename(const char *from, const char *to)
1547 struct fuse_context *ctxt = fuse_get_context();
1548 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1551 ext2_ino_t from_ino, to_ino, to_dir_ino, from_dir_ino;
1552 char *temp_to = NULL, *temp_from = NULL;
1554 struct ext2_inode inode;
1555 struct update_dotdot ud;
1558 FUSE2FS_CHECK_CONTEXT(ff);
1560 dbg_printf("%s: renaming %s to %s\n", __func__, from, to);
1561 pthread_mutex_lock(&ff->bfl);
1562 if (!fs_can_allocate(ff, 5)) {
1567 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, from, &from_ino);
1568 if (err || from_ino == 0) {
1569 ret = translate_error(fs, 0, err);
1573 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, to, &to_ino);
1574 if (err && err != EXT2_ET_FILE_NOT_FOUND) {
1575 ret = translate_error(fs, 0, err);
1579 if (err == EXT2_ET_FILE_NOT_FOUND)
1582 /* Already the same file? */
1583 if (to_ino != 0 && to_ino == from_ino) {
1588 temp_to = strdup(to);
1594 temp_from = strdup(from);
1600 /* Find parent dir of the source and check write access */
1601 cp = strrchr(temp_from, '/');
1609 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_from,
1613 ret = translate_error(fs, 0, err);
1616 if (from_dir_ino == 0) {
1621 ret = check_inum_access(fs, from_dir_ino, W_OK);
1625 /* Find parent dir of the destination and check write access */
1626 cp = strrchr(temp_to, '/');
1634 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_to,
1638 ret = translate_error(fs, 0, err);
1641 if (to_dir_ino == 0) {
1646 ret = check_inum_access(fs, to_dir_ino, W_OK);
1650 /* If the target exists, unlink it first */
1652 err = ext2fs_read_inode(fs, to_ino, &inode);
1654 ret = translate_error(fs, to_ino, err);
1658 dbg_printf("%s: unlinking %s ino=%d\n", __func__,
1659 LINUX_S_ISDIR(inode.i_mode) ? "dir" : "file",
1661 if (LINUX_S_ISDIR(inode.i_mode))
1662 ret = __op_rmdir(ff, to);
1664 ret = __op_unlink(ff, to);
1669 /* Get ready to do the move */
1670 err = ext2fs_read_inode(fs, from_ino, &inode);
1672 ret = translate_error(fs, from_ino, err);
1676 /* Link in the new file */
1677 dbg_printf("%s: linking ino=%d/path=%s to dir=%d\n", __func__,
1678 from_ino, cp + 1, to_dir_ino);
1679 err = ext2fs_link(fs, to_dir_ino, cp + 1, from_ino,
1680 ext2_file_type(inode.i_mode));
1681 if (err == EXT2_ET_DIR_NO_SPACE) {
1682 err = ext2fs_expand_dir(fs, to_dir_ino);
1684 ret = translate_error(fs, to_dir_ino, err);
1688 err = ext2fs_link(fs, to_dir_ino, cp + 1, from_ino,
1689 ext2_file_type(inode.i_mode));
1692 ret = translate_error(fs, to_dir_ino, err);
1696 /* Update '..' pointer if dir */
1697 err = ext2fs_read_inode(fs, from_ino, &inode);
1699 ret = translate_error(fs, from_ino, err);
1703 if (LINUX_S_ISDIR(inode.i_mode)) {
1704 ud.new_dotdot = to_dir_ino;
1705 dbg_printf("%s: updating .. entry for dir=%d\n", __func__,
1707 err = ext2fs_dir_iterate2(fs, from_ino, 0, NULL,
1708 update_dotdot_helper, &ud);
1710 ret = translate_error(fs, from_ino, err);
1714 /* Decrease from_dir_ino's links_count */
1715 dbg_printf("%s: moving linkcount from dir=%d to dir=%d\n",
1716 __func__, from_dir_ino, to_dir_ino);
1717 err = ext2fs_read_inode(fs, from_dir_ino, &inode);
1719 ret = translate_error(fs, from_dir_ino, err);
1722 inode.i_links_count--;
1723 err = ext2fs_write_inode(fs, from_dir_ino, &inode);
1725 ret = translate_error(fs, from_dir_ino, err);
1729 /* Increase to_dir_ino's links_count */
1730 err = ext2fs_read_inode(fs, to_dir_ino, &inode);
1732 ret = translate_error(fs, to_dir_ino, err);
1735 inode.i_links_count++;
1736 err = ext2fs_write_inode(fs, to_dir_ino, &inode);
1738 ret = translate_error(fs, to_dir_ino, err);
1743 /* Update timestamps */
1744 ret = update_ctime(fs, from_ino, NULL);
1748 ret = update_mtime(fs, to_dir_ino, NULL);
1752 /* Remove the old file */
1753 ret = unlink_file_by_name(fs, from);
1757 /* Flush the whole mess out */
1758 err = ext2fs_flush2(fs, 0);
1760 ret = translate_error(fs, 0, err);
1766 pthread_mutex_unlock(&ff->bfl);
1770 static int op_link(const char *src, const char *dest)
1772 struct fuse_context *ctxt = fuse_get_context();
1773 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1778 ext2_ino_t parent, ino;
1779 struct ext2_inode_large inode;
1782 FUSE2FS_CHECK_CONTEXT(ff);
1784 dbg_printf("%s: src=%s dest=%s\n", __func__, src, dest);
1785 temp_path = strdup(dest);
1790 node_name = strrchr(temp_path, '/');
1799 pthread_mutex_lock(&ff->bfl);
1800 if (!fs_can_allocate(ff, 2)) {
1805 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
1813 ret = check_inum_access(fs, parent, W_OK);
1818 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, src, &ino);
1819 if (err || ino == 0) {
1820 ret = translate_error(fs, 0, err);
1824 memset(&inode, 0, sizeof(inode));
1825 err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
1828 ret = translate_error(fs, ino, err);
1832 inode.i_links_count++;
1833 ret = update_ctime(fs, ino, &inode);
1837 err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
1840 ret = translate_error(fs, ino, err);
1844 dbg_printf("%s: linking ino=%d/name=%s to dir=%d\n", __func__, ino,
1846 err = ext2fs_link(fs, parent, node_name, ino,
1847 ext2_file_type(inode.i_mode));
1848 if (err == EXT2_ET_DIR_NO_SPACE) {
1849 err = ext2fs_expand_dir(fs, parent);
1851 ret = translate_error(fs, parent, err);
1855 err = ext2fs_link(fs, parent, node_name, ino,
1856 ext2_file_type(inode.i_mode));
1859 ret = translate_error(fs, parent, err);
1863 ret = update_mtime(fs, parent, NULL);
1868 pthread_mutex_unlock(&ff->bfl);
1874 static int op_chmod(const char *path, mode_t mode)
1876 struct fuse_context *ctxt = fuse_get_context();
1877 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1881 struct ext2_inode_large inode;
1884 FUSE2FS_CHECK_CONTEXT(ff);
1886 pthread_mutex_lock(&ff->bfl);
1887 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
1889 ret = translate_error(fs, 0, err);
1892 dbg_printf("%s: path=%s mode=0%o ino=%d\n", __func__, path, mode, ino);
1894 memset(&inode, 0, sizeof(inode));
1895 err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
1898 ret = translate_error(fs, ino, err);
1902 if (ctxt->uid != 0 && ctxt->uid != inode.i_uid) {
1908 * XXX: We should really check that the inode gid is not in /any/
1909 * of the user's groups, but FUSE only tells us about the primary
1912 if (ctxt->uid != 0 && ctxt->gid != inode.i_gid)
1915 inode.i_mode &= ~0xFFF;
1916 inode.i_mode |= mode & 0xFFF;
1917 ret = update_ctime(fs, ino, &inode);
1921 err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
1924 ret = translate_error(fs, ino, err);
1929 pthread_mutex_unlock(&ff->bfl);
1933 static int op_chown(const char *path, uid_t owner, gid_t group)
1935 struct fuse_context *ctxt = fuse_get_context();
1936 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1940 struct ext2_inode_large inode;
1943 FUSE2FS_CHECK_CONTEXT(ff);
1945 pthread_mutex_lock(&ff->bfl);
1946 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
1948 ret = translate_error(fs, 0, err);
1951 dbg_printf("%s: path=%s owner=%d group=%d ino=%d\n", __func__,
1952 path, owner, group, ino);
1954 memset(&inode, 0, sizeof(inode));
1955 err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
1958 ret = translate_error(fs, ino, err);
1962 /* FUSE seems to feed us ~0 to mean "don't change" */
1963 if (owner != (uid_t) ~0) {
1964 /* Only root gets to change UID. */
1965 if (ctxt->uid != 0 &&
1966 !(inode.i_uid == ctxt->uid && owner == ctxt->uid)) {
1970 inode.i_uid = owner;
1973 if (group != (gid_t) ~0) {
1974 /* Only root or the owner get to change GID. */
1975 if (ctxt->uid != 0 && inode.i_uid != ctxt->uid) {
1980 /* XXX: We /should/ check group membership but FUSE */
1981 inode.i_gid = group;
1984 ret = update_ctime(fs, ino, &inode);
1988 err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
1991 ret = translate_error(fs, ino, err);
1996 pthread_mutex_unlock(&ff->bfl);
2000 static int op_truncate(const char *path, off_t len)
2002 struct fuse_context *ctxt = fuse_get_context();
2003 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2010 FUSE2FS_CHECK_CONTEXT(ff);
2012 pthread_mutex_lock(&ff->bfl);
2013 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2014 if (err || ino == 0) {
2015 ret = translate_error(fs, 0, err);
2018 dbg_printf("%s: ino=%d len=%jd\n", __func__, ino, len);
2020 ret = check_inum_access(fs, ino, W_OK);
2024 err = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &file);
2026 ret = translate_error(fs, ino, err);
2030 err = ext2fs_file_set_size2(file, len);
2032 ret = translate_error(fs, ino, err);
2037 err = ext2fs_file_close(file);
2041 ret = translate_error(fs, ino, err);
2045 ret = update_mtime(fs, ino, NULL);
2048 pthread_mutex_unlock(&ff->bfl);
2053 static void detect_linux_executable_open(int kernel_flags, int *access_check,
2054 int *e2fs_open_flags)
2057 * On Linux, execve will bleed __FMODE_EXEC into the file mode flags,
2058 * and FUSE is more than happy to let that slip through.
2060 if (kernel_flags & 0x20) {
2061 *access_check = X_OK;
2062 *e2fs_open_flags &= ~EXT2_FILE_WRITE;
2066 static void detect_linux_executable_open(int kernel_flags, int *access_check,
2067 int *e2fs_open_flags)
2071 #endif /* __linux__ */
2073 static int __op_open(struct fuse2fs *ff, const char *path,
2074 struct fuse_file_info *fp)
2076 ext2_filsys fs = ff->fs;
2078 struct fuse2fs_file_handle *file;
2079 int check = 0, ret = 0;
2081 dbg_printf("%s: path=%s\n", __func__, path);
2082 err = ext2fs_get_mem(sizeof(*file), &file);
2084 return translate_error(fs, 0, err);
2085 file->magic = FUSE2FS_FILE_MAGIC;
2087 file->open_flags = 0;
2088 switch (fp->flags & O_ACCMODE) {
2094 file->open_flags |= EXT2_FILE_WRITE;
2097 check = R_OK | W_OK;
2098 file->open_flags |= EXT2_FILE_WRITE;
2102 detect_linux_executable_open(fp->flags, &check, &file->open_flags);
2104 if (fp->flags & O_CREAT)
2105 file->open_flags |= EXT2_FILE_CREATE;
2107 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &file->ino);
2108 if (err || file->ino == 0) {
2109 ret = translate_error(fs, 0, err);
2112 dbg_printf("%s: ino=%d\n", __func__, file->ino);
2114 ret = check_inum_access(fs, file->ino, check);
2117 * In a regular (Linux) fs driver, the kernel will open
2118 * binaries for reading if the user has --x privileges (i.e.
2119 * execute without read). Since the kernel doesn't have any
2120 * way to tell us if it's opening a file via execve, we'll
2121 * just assume that allowing access is ok if asking for ro mode
2122 * fails but asking for x mode succeeds. Of course we can
2123 * also employ undocumented hacks (see above).
2125 if (check == R_OK) {
2126 ret = check_inum_access(fs, file->ino, X_OK);
2132 fp->fh = (uintptr_t)file;
2136 ext2fs_free_mem(&file);
2140 static int op_open(const char *path, struct fuse_file_info *fp)
2142 struct fuse_context *ctxt = fuse_get_context();
2143 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2146 FUSE2FS_CHECK_CONTEXT(ff);
2147 pthread_mutex_lock(&ff->bfl);
2148 ret = __op_open(ff, path, fp);
2149 pthread_mutex_unlock(&ff->bfl);
2153 static int op_read(const char *path EXT2FS_ATTR((unused)), char *buf,
2154 size_t len, off_t offset,
2155 struct fuse_file_info *fp)
2157 struct fuse_context *ctxt = fuse_get_context();
2158 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2159 struct fuse2fs_file_handle *fh =
2160 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2164 unsigned int got = 0;
2167 FUSE2FS_CHECK_CONTEXT(ff);
2169 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2170 dbg_printf("%s: ino=%d off=%jd len=%jd\n", __func__, fh->ino, offset,
2172 pthread_mutex_lock(&ff->bfl);
2173 err = ext2fs_file_open(fs, fh->ino, fh->open_flags, &efp);
2175 ret = translate_error(fs, fh->ino, err);
2179 err = ext2fs_file_llseek(efp, offset, SEEK_SET, NULL);
2181 ret = translate_error(fs, fh->ino, err);
2185 err = ext2fs_file_read(efp, buf, len, &got);
2187 ret = translate_error(fs, fh->ino, err);
2192 err = ext2fs_file_close(efp);
2196 ret = translate_error(fs, fh->ino, err);
2200 if (fs_writeable(fs)) {
2201 ret = update_atime(fs, fh->ino);
2206 pthread_mutex_unlock(&ff->bfl);
2207 return got ? (int) got : ret;
2210 static int op_write(const char *path EXT2FS_ATTR((unused)),
2211 const char *buf, size_t len, off_t offset,
2212 struct fuse_file_info *fp)
2214 struct fuse_context *ctxt = fuse_get_context();
2215 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2216 struct fuse2fs_file_handle *fh =
2217 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2221 unsigned int got = 0;
2224 FUSE2FS_CHECK_CONTEXT(ff);
2226 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2227 dbg_printf("%s: ino=%d off=%jd len=%jd\n", __func__, fh->ino, offset,
2229 pthread_mutex_lock(&ff->bfl);
2230 if (!fs_writeable(fs)) {
2235 if (!fs_can_allocate(ff, len / fs->blocksize)) {
2240 err = ext2fs_file_open(fs, fh->ino, fh->open_flags, &efp);
2242 ret = translate_error(fs, fh->ino, err);
2246 err = ext2fs_file_llseek(efp, offset, SEEK_SET, NULL);
2248 ret = translate_error(fs, fh->ino, err);
2252 err = ext2fs_file_write(efp, buf, len, &got);
2254 ret = translate_error(fs, fh->ino, err);
2258 err = ext2fs_file_flush(efp);
2261 ret = translate_error(fs, fh->ino, err);
2266 err = ext2fs_file_close(efp);
2270 ret = translate_error(fs, fh->ino, err);
2274 ret = update_mtime(fs, fh->ino, NULL);
2279 pthread_mutex_unlock(&ff->bfl);
2280 return got ? (int) got : ret;
2283 static int op_release(const char *path EXT2FS_ATTR((unused)),
2284 struct fuse_file_info *fp)
2286 struct fuse_context *ctxt = fuse_get_context();
2287 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2288 struct fuse2fs_file_handle *fh =
2289 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2294 FUSE2FS_CHECK_CONTEXT(ff);
2296 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2297 dbg_printf("%s: ino=%d\n", __func__, fh->ino);
2298 pthread_mutex_lock(&ff->bfl);
2299 if (fs_writeable(fs) && fh->open_flags & EXT2_FILE_WRITE) {
2300 err = ext2fs_flush2(fs, EXT2_FLAG_FLUSH_NO_SYNC);
2302 ret = translate_error(fs, fh->ino, err);
2305 pthread_mutex_unlock(&ff->bfl);
2307 ext2fs_free_mem(&fh);
2312 static int op_fsync(const char *path EXT2FS_ATTR((unused)),
2313 int datasync EXT2FS_ATTR((unused)),
2314 struct fuse_file_info *fp)
2316 struct fuse_context *ctxt = fuse_get_context();
2317 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2318 struct fuse2fs_file_handle *fh =
2319 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2324 FUSE2FS_CHECK_CONTEXT(ff);
2326 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2327 dbg_printf("%s: ino=%d\n", __func__, fh->ino);
2328 /* For now, flush everything, even if it's slow */
2329 pthread_mutex_lock(&ff->bfl);
2330 if (fs_writeable(fs) && fh->open_flags & EXT2_FILE_WRITE) {
2331 err = ext2fs_flush2(fs, 0);
2333 ret = translate_error(fs, fh->ino, err);
2335 pthread_mutex_unlock(&ff->bfl);
2340 static int op_statfs(const char *path EXT2FS_ATTR((unused)),
2341 struct statvfs *buf)
2343 struct fuse_context *ctxt = fuse_get_context();
2344 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2347 blk64_t overhead, reserved, free;
2349 FUSE2FS_CHECK_CONTEXT(ff);
2351 dbg_printf("%s: path=%s\n", __func__, path);
2352 buf->f_bsize = fs->blocksize;
2358 overhead = fs->desc_blocks +
2359 fs->group_desc_count *
2360 (fs->inode_blocks_per_group + 2);
2361 reserved = ext2fs_r_blocks_count(fs->super);
2363 reserved = ext2fs_blocks_count(fs->super) / 10;
2364 free = ext2fs_free_blocks_count(fs->super);
2366 buf->f_blocks = ext2fs_blocks_count(fs->super) - overhead;
2367 buf->f_bfree = free;
2368 if (free < reserved)
2371 buf->f_bavail = free - reserved;
2372 buf->f_files = fs->super->s_inodes_count;
2373 buf->f_ffree = fs->super->s_free_inodes_count;
2374 buf->f_favail = fs->super->s_free_inodes_count;
2375 f = (uint64_t *)fs->super->s_uuid;
2381 if (fs->flags & EXT2_FLAG_RW)
2382 buf->f_flag |= ST_RDONLY;
2383 buf->f_namemax = EXT2_NAME_LEN;
2388 typedef errcode_t (*xattr_xlate_get)(void **cooked_buf, size_t *cooked_sz,
2389 const void *raw_buf, size_t raw_sz);
2390 typedef errcode_t (*xattr_xlate_set)(const void *cooked_buf, size_t cooked_sz,
2391 const void **raw_buf, size_t *raw_sz);
2392 struct xattr_translate {
2394 xattr_xlate_get get;
2395 xattr_xlate_set set;
2398 #define XATTR_TRANSLATOR(p, g, s) \
2400 .get = (xattr_xlate_get)(g), \
2401 .set = (xattr_xlate_set)(s)}
2403 static struct xattr_translate xattr_translators[] = {
2404 #ifdef TRANSLATE_LINUX_ACLS
2405 XATTR_TRANSLATOR(ACL_EA_ACCESS, ext4_to_fuse_acl, fuse_to_ext4_acl),
2406 XATTR_TRANSLATOR(ACL_EA_DEFAULT, ext4_to_fuse_acl, fuse_to_ext4_acl),
2408 XATTR_TRANSLATOR(NULL, NULL, NULL),
2410 #undef XATTR_TRANSLATOR
2412 static int op_getxattr(const char *path, const char *key, char *value,
2415 struct fuse_context *ctxt = fuse_get_context();
2416 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2418 struct ext2_xattr_handle *h;
2419 struct xattr_translate *xt;
2426 FUSE2FS_CHECK_CONTEXT(ff);
2428 pthread_mutex_lock(&ff->bfl);
2429 if (!ext2fs_has_feature_xattr(fs->super)) {
2434 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2435 if (err || ino == 0) {
2436 ret = translate_error(fs, 0, err);
2439 dbg_printf("%s: ino=%d\n", __func__, ino);
2441 ret = check_inum_access(fs, ino, R_OK);
2445 err = ext2fs_xattrs_open(fs, ino, &h);
2447 ret = translate_error(fs, ino, err);
2451 err = ext2fs_xattrs_read(h);
2453 ret = translate_error(fs, ino, err);
2457 err = ext2fs_xattr_get(h, key, &ptr, &plen);
2459 ret = translate_error(fs, ino, err);
2463 for (xt = xattr_translators; xt->prefix != NULL; xt++) {
2464 if (strncmp(key, xt->prefix, strlen(xt->prefix)) == 0) {
2465 err = xt->get(&cptr, &clen, ptr, plen);
2468 ext2fs_free_mem(&ptr);
2476 } else if (len < plen) {
2479 memcpy(value, ptr, plen);
2484 ext2fs_free_mem(&ptr);
2486 err = ext2fs_xattrs_close(&h);
2488 ret = translate_error(fs, ino, err);
2490 pthread_mutex_unlock(&ff->bfl);
2495 static int count_buffer_space(char *name, char *value EXT2FS_ATTR((unused)),
2496 size_t value_len EXT2FS_ATTR((unused)),
2499 unsigned int *x = data;
2501 *x = *x + strlen(name) + 1;
2505 static int copy_names(char *name, char *value EXT2FS_ATTR((unused)),
2506 size_t value_len EXT2FS_ATTR((unused)), void *data)
2510 strncpy(*b, name, strlen(name));
2511 *b = *b + strlen(name) + 1;
2516 static int op_listxattr(const char *path, char *names, size_t len)
2518 struct fuse_context *ctxt = fuse_get_context();
2519 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2521 struct ext2_xattr_handle *h;
2527 FUSE2FS_CHECK_CONTEXT(ff);
2529 pthread_mutex_lock(&ff->bfl);
2530 if (!ext2fs_has_feature_xattr(fs->super)) {
2535 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2536 if (err || ino == 0) {
2537 ret = translate_error(fs, ino, err);
2540 dbg_printf("%s: ino=%d\n", __func__, ino);
2542 ret = check_inum_access(fs, ino, R_OK);
2546 err = ext2fs_xattrs_open(fs, ino, &h);
2548 ret = translate_error(fs, ino, err);
2552 err = ext2fs_xattrs_read(h);
2554 ret = translate_error(fs, ino, err);
2558 /* Count buffer space needed for names */
2560 err = ext2fs_xattrs_iterate(h, count_buffer_space, &bufsz);
2562 ret = translate_error(fs, ino, err);
2569 } else if (len < bufsz) {
2574 /* Copy names out */
2575 memset(names, 0, len);
2576 err = ext2fs_xattrs_iterate(h, copy_names, &names);
2578 ret = translate_error(fs, ino, err);
2583 err = ext2fs_xattrs_close(&h);
2585 ret = translate_error(fs, ino, err);
2587 pthread_mutex_unlock(&ff->bfl);
2592 static int op_setxattr(const char *path EXT2FS_ATTR((unused)),
2593 const char *key, const char *value,
2594 size_t len, int flags EXT2FS_ATTR((unused)))
2596 struct fuse_context *ctxt = fuse_get_context();
2597 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2599 struct ext2_xattr_handle *h;
2600 struct xattr_translate *xt;
2607 FUSE2FS_CHECK_CONTEXT(ff);
2609 pthread_mutex_lock(&ff->bfl);
2610 if (!ext2fs_has_feature_xattr(fs->super)) {
2615 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2616 if (err || ino == 0) {
2617 ret = translate_error(fs, 0, err);
2620 dbg_printf("%s: ino=%d\n", __func__, ino);
2622 ret = check_inum_access(fs, ino, W_OK);
2623 if (ret == -EACCES) {
2629 err = ext2fs_xattrs_open(fs, ino, &h);
2631 ret = translate_error(fs, ino, err);
2635 err = ext2fs_xattrs_read(h);
2637 ret = translate_error(fs, ino, err);
2643 for (xt = xattr_translators; xt->prefix != NULL; xt++) {
2644 if (strncmp(key, xt->prefix, strlen(xt->prefix)) == 0) {
2645 err = xt->set(value, len, &cvalue, &clen);
2651 err = ext2fs_xattr_set(h, key, cvalue, clen);
2653 ret = translate_error(fs, ino, err);
2657 err = ext2fs_xattrs_write(h);
2659 ret = translate_error(fs, ino, err);
2663 ret = update_ctime(fs, ino, NULL);
2665 if (cvalue != value)
2666 ext2fs_free_mem(&cvalue);
2668 err = ext2fs_xattrs_close(&h);
2670 ret = translate_error(fs, ino, err);
2672 pthread_mutex_unlock(&ff->bfl);
2677 static int op_removexattr(const char *path, const char *key)
2679 struct fuse_context *ctxt = fuse_get_context();
2680 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2682 struct ext2_xattr_handle *h;
2687 FUSE2FS_CHECK_CONTEXT(ff);
2689 pthread_mutex_lock(&ff->bfl);
2690 if (!ext2fs_has_feature_xattr(fs->super)) {
2695 if (!fs_can_allocate(ff, 1)) {
2700 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2701 if (err || ino == 0) {
2702 ret = translate_error(fs, 0, err);
2705 dbg_printf("%s: ino=%d\n", __func__, ino);
2707 ret = check_inum_access(fs, ino, W_OK);
2711 err = ext2fs_xattrs_open(fs, ino, &h);
2713 ret = translate_error(fs, ino, err);
2717 err = ext2fs_xattrs_read(h);
2719 ret = translate_error(fs, ino, err);
2723 err = ext2fs_xattr_remove(h, key);
2725 ret = translate_error(fs, ino, err);
2729 err = ext2fs_xattrs_write(h);
2731 ret = translate_error(fs, ino, err);
2735 ret = update_ctime(fs, ino, NULL);
2737 err = ext2fs_xattrs_close(&h);
2739 ret = translate_error(fs, ino, err);
2741 pthread_mutex_unlock(&ff->bfl);
2746 struct readdir_iter {
2748 fuse_fill_dir_t func;
2751 static int op_readdir_iter(ext2_ino_t dir EXT2FS_ATTR((unused)),
2752 int entry EXT2FS_ATTR((unused)),
2753 struct ext2_dir_entry *dirent,
2754 int offset EXT2FS_ATTR((unused)),
2755 int blocksize EXT2FS_ATTR((unused)),
2756 char *buf EXT2FS_ATTR((unused)), void *data)
2758 struct readdir_iter *i = data;
2759 char namebuf[EXT2_NAME_LEN + 1];
2762 memcpy(namebuf, dirent->name, dirent->name_len & 0xFF);
2763 namebuf[dirent->name_len & 0xFF] = 0;
2764 ret = i->func(i->buf, namebuf, NULL, 0);
2766 return DIRENT_ABORT;
2771 static int op_readdir(const char *path EXT2FS_ATTR((unused)),
2772 void *buf, fuse_fill_dir_t fill_func,
2773 off_t offset EXT2FS_ATTR((unused)),
2774 struct fuse_file_info *fp)
2776 struct fuse_context *ctxt = fuse_get_context();
2777 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2778 struct fuse2fs_file_handle *fh =
2779 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2782 struct readdir_iter i;
2785 FUSE2FS_CHECK_CONTEXT(ff);
2787 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2788 dbg_printf("%s: ino=%d\n", __func__, fh->ino);
2789 pthread_mutex_lock(&ff->bfl);
2792 err = ext2fs_dir_iterate2(fs, fh->ino, 0, NULL, op_readdir_iter, &i);
2794 ret = translate_error(fs, fh->ino, err);
2798 if (fs_writeable(fs)) {
2799 ret = update_atime(fs, fh->ino);
2804 pthread_mutex_unlock(&ff->bfl);
2808 static int op_access(const char *path, int mask)
2810 struct fuse_context *ctxt = fuse_get_context();
2811 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2817 FUSE2FS_CHECK_CONTEXT(ff);
2819 dbg_printf("%s: path=%s mask=0x%x\n", __func__, path, mask);
2820 pthread_mutex_lock(&ff->bfl);
2821 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2822 if (err || ino == 0) {
2823 ret = translate_error(fs, 0, err);
2827 ret = check_inum_access(fs, ino, mask);
2832 pthread_mutex_unlock(&ff->bfl);
2836 static int op_create(const char *path, mode_t mode, struct fuse_file_info *fp)
2838 struct fuse_context *ctxt = fuse_get_context();
2839 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2841 ext2_ino_t parent, child;
2846 struct ext2_inode_large inode;
2849 FUSE2FS_CHECK_CONTEXT(ff);
2851 dbg_printf("%s: path=%s mode=0%o\n", __func__, path, mode);
2852 temp_path = strdup(path);
2857 node_name = strrchr(temp_path, '/');
2866 pthread_mutex_lock(&ff->bfl);
2867 if (!fs_can_allocate(ff, 1)) {
2872 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
2875 ret = translate_error(fs, 0, err);
2879 ret = check_inum_access(fs, parent, W_OK);
2885 filetype = ext2_file_type(mode);
2887 err = ext2fs_new_inode(fs, parent, mode, 0, &child);
2889 ret = translate_error(fs, parent, err);
2893 dbg_printf("%s: creating ino=%d/name=%s in dir=%d\n", __func__, child,
2895 err = ext2fs_link(fs, parent, node_name, child, filetype);
2896 if (err == EXT2_ET_DIR_NO_SPACE) {
2897 err = ext2fs_expand_dir(fs, parent);
2899 ret = translate_error(fs, parent, err);
2903 err = ext2fs_link(fs, parent, node_name, child,
2907 ret = translate_error(fs, parent, err);
2911 ret = update_mtime(fs, parent, NULL);
2915 memset(&inode, 0, sizeof(inode));
2916 inode.i_mode = mode;
2917 inode.i_links_count = 1;
2918 inode.i_extra_isize = sizeof(struct ext2_inode_large) -
2919 EXT2_GOOD_OLD_INODE_SIZE;
2920 inode.i_uid = ctxt->uid;
2921 inode.i_gid = ctxt->gid;
2922 if (ext2fs_has_feature_extents(fs->super)) {
2923 ext2_extent_handle_t handle;
2925 inode.i_flags &= ~EXT4_EXTENTS_FL;
2926 ret = ext2fs_extent_open2(fs, child,
2927 (struct ext2_inode *)&inode, &handle);
2930 ext2fs_extent_free(handle);
2933 err = ext2fs_write_new_inode(fs, child, (struct ext2_inode *)&inode);
2935 ret = translate_error(fs, child, err);
2939 inode.i_generation = ff->next_generation++;
2941 err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode,
2944 ret = translate_error(fs, child, err);
2948 ext2fs_inode_alloc_stats2(fs, child, 1, 0);
2950 ret = __op_open(ff, path, fp);
2954 pthread_mutex_unlock(&ff->bfl);
2960 static int op_ftruncate(const char *path EXT2FS_ATTR((unused)),
2961 off_t len, struct fuse_file_info *fp)
2963 struct fuse_context *ctxt = fuse_get_context();
2964 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2965 struct fuse2fs_file_handle *fh =
2966 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2972 FUSE2FS_CHECK_CONTEXT(ff);
2974 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2975 dbg_printf("%s: ino=%d len=%jd\n", __func__, fh->ino, len);
2976 pthread_mutex_lock(&ff->bfl);
2977 if (!fs_writeable(fs)) {
2982 err = ext2fs_file_open(fs, fh->ino, fh->open_flags, &efp);
2984 ret = translate_error(fs, fh->ino, err);
2988 err = ext2fs_file_set_size2(efp, len);
2990 ret = translate_error(fs, fh->ino, err);
2995 err = ext2fs_file_close(efp);
2999 ret = translate_error(fs, fh->ino, err);
3003 ret = update_mtime(fs, fh->ino, NULL);
3008 pthread_mutex_unlock(&ff->bfl);
3012 static int op_fgetattr(const char *path EXT2FS_ATTR((unused)),
3013 struct stat *statbuf,
3014 struct fuse_file_info *fp)
3016 struct fuse_context *ctxt = fuse_get_context();
3017 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3019 struct fuse2fs_file_handle *fh =
3020 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
3023 FUSE2FS_CHECK_CONTEXT(ff);
3025 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3026 dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3027 pthread_mutex_lock(&ff->bfl);
3028 ret = stat_inode(fs, fh->ino, statbuf);
3029 pthread_mutex_unlock(&ff->bfl);
3034 static int op_utimens(const char *path, const struct timespec ctv[2])
3036 struct fuse_context *ctxt = fuse_get_context();
3037 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3038 struct timespec tv[2];
3042 struct ext2_inode_large inode;
3045 FUSE2FS_CHECK_CONTEXT(ff);
3047 pthread_mutex_lock(&ff->bfl);
3048 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
3050 ret = translate_error(fs, 0, err);
3053 dbg_printf("%s: ino=%d\n", __func__, ino);
3055 ret = check_inum_access(fs, ino, W_OK);
3059 memset(&inode, 0, sizeof(inode));
3060 err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
3063 ret = translate_error(fs, ino, err);
3070 if (tv[0].tv_nsec == UTIME_NOW)
3072 if (tv[1].tv_nsec == UTIME_NOW)
3074 #endif /* UTIME_NOW */
3076 if (tv[0].tv_nsec != UTIME_OMIT)
3077 EXT4_INODE_SET_XTIME(i_atime, tv, &inode);
3078 if (tv[1].tv_nsec != UTIME_OMIT)
3079 EXT4_INODE_SET_XTIME(i_mtime, tv + 1, &inode);
3080 #endif /* UTIME_OMIT */
3081 ret = update_ctime(fs, ino, &inode);
3085 err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
3088 ret = translate_error(fs, ino, err);
3093 pthread_mutex_unlock(&ff->bfl);
3097 #ifdef SUPPORT_I_FLAGS
3098 static int ioctl_getflags(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3102 struct ext2_inode_large inode;
3104 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3105 dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3106 memset(&inode, 0, sizeof(inode));
3107 err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3110 return translate_error(fs, fh->ino, err);
3112 *(__u32 *)data = inode.i_flags & EXT2_FL_USER_VISIBLE;
3116 #define FUSE2FS_MODIFIABLE_IFLAGS \
3117 (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL | EXT2_NODUMP_FL | \
3118 EXT2_NOATIME_FL | EXT3_JOURNAL_DATA_FL | EXT2_DIRSYNC_FL | \
3121 static int ioctl_setflags(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3125 struct ext2_inode_large inode;
3127 __u32 flags = *(__u32 *)data;
3128 struct fuse_context *ctxt = fuse_get_context();
3130 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3131 dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3132 memset(&inode, 0, sizeof(inode));
3133 err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3136 return translate_error(fs, fh->ino, err);
3138 if (ctxt->uid != 0 && inode.i_uid != ctxt->uid)
3141 if ((inode.i_flags ^ flags) & ~FUSE2FS_MODIFIABLE_IFLAGS)
3144 inode.i_flags = (inode.i_flags & ~FUSE2FS_MODIFIABLE_IFLAGS) |
3145 (flags & FUSE2FS_MODIFIABLE_IFLAGS);
3147 ret = update_ctime(fs, fh->ino, &inode);
3151 err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3154 return translate_error(fs, fh->ino, err);
3159 static int ioctl_getversion(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3163 struct ext2_inode_large inode;
3165 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3166 dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3167 memset(&inode, 0, sizeof(inode));
3168 err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3171 return translate_error(fs, fh->ino, err);
3173 *(__u32 *)data = inode.i_generation;
3177 static int ioctl_setversion(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3181 struct ext2_inode_large inode;
3183 __u32 generation = *(__u32 *)data;
3184 struct fuse_context *ctxt = fuse_get_context();
3186 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3187 dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3188 memset(&inode, 0, sizeof(inode));
3189 err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3192 return translate_error(fs, fh->ino, err);
3194 if (ctxt->uid != 0 && inode.i_uid != ctxt->uid)
3197 inode.i_generation = generation;
3199 ret = update_ctime(fs, fh->ino, &inode);
3203 err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3206 return translate_error(fs, fh->ino, err);
3210 #endif /* SUPPORT_I_FLAGS */
3213 static int ioctl_fitrim(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3216 struct fstrim_range *fr = data;
3217 blk64_t start, end, max_blocks, b, cleared;
3220 start = fr->start / fs->blocksize;
3221 end = (fr->start + fr->len - 1) / fs->blocksize;
3222 dbg_printf("%s: start=%llu end=%llu\n", __func__, start, end);
3224 if (start < fs->super->s_first_data_block)
3225 start = fs->super->s_first_data_block;
3226 if (start >= ext2fs_blocks_count(fs->super))
3227 start = ext2fs_blocks_count(fs->super) - 1;
3229 if (end < fs->super->s_first_data_block)
3230 end = fs->super->s_first_data_block;
3231 if (end >= ext2fs_blocks_count(fs->super))
3232 end = ext2fs_blocks_count(fs->super) - 1;
3235 max_blocks = 2048ULL * 1024 * 1024 / fs->blocksize;
3238 while (start <= end) {
3239 err = ext2fs_find_first_zero_block_bitmap2(fs->block_map,
3240 start, end, &start);
3244 return translate_error(fs, fh->ino, err);
3246 b = start + max_blocks < end ? start + max_blocks : end;
3247 err = ext2fs_find_first_set_block_bitmap2(fs->block_map,
3249 if (err && err != ENOENT)
3250 return translate_error(fs, fh->ino, err);
3251 if (b - start >= fr->minlen) {
3252 err = io_channel_discard(fs->io, start, b - start);
3254 return translate_error(fs, fh->ino, err);
3255 cleared += b - start;
3256 fr->len = cleared * fs->blocksize;
3265 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
3266 static int op_ioctl(const char *path EXT2FS_ATTR((unused)), int cmd,
3267 void *arg EXT2FS_ATTR((unused)),
3268 struct fuse_file_info *fp,
3269 unsigned int flags EXT2FS_ATTR((unused)), void *data)
3271 struct fuse_context *ctxt = fuse_get_context();
3272 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3273 struct fuse2fs_file_handle *fh =
3274 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
3278 FUSE2FS_CHECK_CONTEXT(ff);
3280 pthread_mutex_lock(&ff->bfl);
3281 switch ((unsigned long) cmd) {
3282 #ifdef SUPPORT_I_FLAGS
3283 case EXT2_IOC_GETFLAGS:
3284 ret = ioctl_getflags(fs, fh, data);
3286 case EXT2_IOC_SETFLAGS:
3287 ret = ioctl_setflags(fs, fh, data);
3289 case EXT2_IOC_GETVERSION:
3290 ret = ioctl_getversion(fs, fh, data);
3292 case EXT2_IOC_SETVERSION:
3293 ret = ioctl_setversion(fs, fh, data);
3298 ret = ioctl_fitrim(fs, fh, data);
3302 dbg_printf("%s: Unknown ioctl %d\n", __func__, cmd);
3305 pthread_mutex_unlock(&ff->bfl);
3309 #endif /* FUSE 28 */
3311 static int op_bmap(const char *path, size_t blocksize EXT2FS_ATTR((unused)),
3314 struct fuse_context *ctxt = fuse_get_context();
3315 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3321 FUSE2FS_CHECK_CONTEXT(ff);
3323 pthread_mutex_lock(&ff->bfl);
3324 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
3326 ret = translate_error(fs, 0, err);
3329 dbg_printf("%s: ino=%d blk=%"PRIu64"\n", __func__, ino, *idx);
3331 err = ext2fs_bmap2(fs, ino, NULL, NULL, 0, *idx, 0, (blk64_t *)idx);
3333 ret = translate_error(fs, ino, err);
3338 pthread_mutex_unlock(&ff->bfl);
3342 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
3343 # ifdef SUPPORT_FALLOCATE
3344 static int fallocate_helper(struct fuse_file_info *fp, int mode, off_t offset,
3347 struct fuse_context *ctxt = fuse_get_context();
3348 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3349 struct fuse2fs_file_handle *fh =
3350 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
3352 struct ext2_inode_large inode;
3358 FUSE2FS_CHECK_CONTEXT(ff);
3360 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3361 start = offset / fs->blocksize;
3362 end = (offset + len - 1) / fs->blocksize;
3363 dbg_printf("%s: ino=%d mode=0x%x start=%jd end=%llu\n", __func__,
3364 fh->ino, mode, offset / fs->blocksize, end);
3365 if (!fs_can_allocate(ff, len / fs->blocksize))
3368 memset(&inode, 0, sizeof(inode));
3369 err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3373 fsize = EXT2_I_SIZE(&inode);
3375 /* Allocate a bunch of blocks */
3376 flags = (mode & FL_KEEP_SIZE_FLAG ? 0 :
3377 EXT2_FALLOCATE_INIT_BEYOND_EOF);
3378 err = ext2fs_fallocate(fs, flags, fh->ino,
3379 (struct ext2_inode *)&inode,
3380 ~0ULL, start, end - start + 1);
3381 if (err && err != EXT2_ET_BLOCK_ALLOC_FAIL)
3382 return translate_error(fs, fh->ino, err);
3385 if (!(mode & FL_KEEP_SIZE_FLAG)) {
3386 if ((__u64) offset + len > fsize) {
3387 err = ext2fs_inode_size_set(fs,
3388 (struct ext2_inode *)&inode,
3391 return translate_error(fs, fh->ino, err);
3395 err = update_mtime(fs, fh->ino, &inode);
3399 err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3402 return translate_error(fs, fh->ino, err);
3407 static errcode_t clean_block_middle(ext2_filsys fs, ext2_ino_t ino,
3408 struct ext2_inode_large *inode, off_t offset,
3409 off_t len, char **buf)
3416 residue = offset % fs->blocksize;
3421 err = ext2fs_get_mem(fs->blocksize, buf);
3426 err = ext2fs_bmap2(fs, ino, (struct ext2_inode *)inode, *buf, 0,
3427 offset / fs->blocksize, &retflags, &blk);
3430 if (!blk || (retflags & BMAP_RET_UNINIT))
3433 err = io_channel_read_blk(fs->io, blk, 1, *buf);
3437 memset(*buf + residue, 0, len);
3439 return io_channel_write_blk(fs->io, blk, 1, *buf);
3442 static errcode_t clean_block_edge(ext2_filsys fs, ext2_ino_t ino,
3443 struct ext2_inode_large *inode, off_t offset,
3444 int clean_before, char **buf)
3451 residue = offset % fs->blocksize;
3456 err = ext2fs_get_mem(fs->blocksize, buf);
3461 err = ext2fs_bmap2(fs, ino, (struct ext2_inode *)inode, *buf, 0,
3462 offset / fs->blocksize, &retflags, &blk);
3466 err = io_channel_read_blk(fs->io, blk, 1, *buf);
3469 if (!blk || (retflags & BMAP_RET_UNINIT))
3473 memset(*buf, 0, residue);
3475 memset(*buf + residue, 0, fs->blocksize - residue);
3477 return io_channel_write_blk(fs->io, blk, 1, *buf);
3480 static int punch_helper(struct fuse_file_info *fp, int mode, off_t offset,
3483 struct fuse_context *ctxt = fuse_get_context();
3484 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3485 struct fuse2fs_file_handle *fh =
3486 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
3488 struct ext2_inode_large inode;
3493 FUSE2FS_CHECK_CONTEXT(ff);
3495 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3496 dbg_printf("%s: offset=%jd len=%jd\n", __func__, offset, len);
3498 /* kernel ext4 punch requires this flag to be set */
3499 if (!(mode & FL_KEEP_SIZE_FLAG))
3502 /* Punch out a bunch of blocks */
3503 start = (offset + fs->blocksize - 1) / fs->blocksize;
3504 end = (offset + len - fs->blocksize) / fs->blocksize;
3505 dbg_printf("%s: ino=%d mode=0x%x start=%llu end=%llu\n", __func__,
3506 fh->ino, mode, start, end);
3508 memset(&inode, 0, sizeof(inode));
3509 err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3512 return translate_error(fs, fh->ino, err);
3514 /* Zero everything before the first block and after the last block */
3515 if ((offset / fs->blocksize) == ((offset + len) / fs->blocksize))
3516 err = clean_block_middle(fs, fh->ino, &inode, offset,
3519 err = clean_block_edge(fs, fh->ino, &inode, offset, 0, &buf);
3521 err = clean_block_edge(fs, fh->ino, &inode,
3522 offset + len, 1, &buf);
3525 ext2fs_free_mem(&buf);
3527 return translate_error(fs, fh->ino, err);
3529 /* Unmap full blocks in the middle */
3531 err = ext2fs_punch(fs, fh->ino, (struct ext2_inode *)&inode,
3534 return translate_error(fs, fh->ino, err);
3537 err = update_mtime(fs, fh->ino, &inode);
3541 err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3544 return translate_error(fs, fh->ino, err);
3549 static int op_fallocate(const char *path EXT2FS_ATTR((unused)), int mode,
3550 off_t offset, off_t len,
3551 struct fuse_file_info *fp)
3553 struct fuse_context *ctxt = fuse_get_context();
3554 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3555 ext2_filsys fs = ff->fs;
3558 /* Catch unknown flags */
3559 if (mode & ~(FL_PUNCH_HOLE_FLAG | FL_KEEP_SIZE_FLAG))
3562 pthread_mutex_lock(&ff->bfl);
3563 if (!fs_writeable(fs)) {
3567 if (mode & FL_PUNCH_HOLE_FLAG)
3568 ret = punch_helper(fp, mode, offset, len);
3570 ret = fallocate_helper(fp, mode, offset, len);
3572 pthread_mutex_unlock(&ff->bfl);
3576 # endif /* SUPPORT_FALLOCATE */
3577 #endif /* FUSE 29 */
3579 static struct fuse_operations fs_ops = {
3581 .destroy = op_destroy,
3582 .getattr = op_getattr,
3583 .readlink = op_readlink,
3586 .unlink = op_unlink,
3588 .symlink = op_symlink,
3589 .rename = op_rename,
3593 .truncate = op_truncate,
3597 .statfs = op_statfs,
3598 .release = op_release,
3600 .setxattr = op_setxattr,
3601 .getxattr = op_getxattr,
3602 .listxattr = op_listxattr,
3603 .removexattr = op_removexattr,
3605 .readdir = op_readdir,
3606 .releasedir = op_release,
3607 .fsyncdir = op_fsync,
3608 .access = op_access,
3609 .create = op_create,
3610 .ftruncate = op_ftruncate,
3611 .fgetattr = op_fgetattr,
3612 .utimens = op_utimens,
3613 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
3614 # if defined(UTIME_NOW) || defined(UTIME_OMIT)
3615 .flag_utime_omit_ok = 1,
3623 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
3625 .flag_nullpath_ok = 1,
3627 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
3629 # ifdef SUPPORT_FALLOCATE
3630 .fallocate = op_fallocate,
3635 static int get_random_bytes(void *p, size_t sz)
3640 fd = open("/dev/urandom", O_RDONLY);
3642 perror("/dev/urandom");
3646 r = read(fd, p, sz);
3649 return (size_t) r == sz;
3658 #define FUSE2FS_OPT(t, p, v) { t, offsetof(struct fuse2fs, p), v }
3660 static struct fuse_opt fuse2fs_opts[] = {
3661 FUSE2FS_OPT("ro", ro, 1),
3662 FUSE2FS_OPT("errors=panic", panic_on_error, 1),
3663 FUSE2FS_OPT("minixdf", minixdf, 1),
3664 FUSE2FS_OPT("fuse2fs_debug", debug, 1),
3665 FUSE2FS_OPT("no_default_opts", no_default_opts, 1),
3667 FUSE_OPT_KEY("-V", FUSE2FS_VERSION),
3668 FUSE_OPT_KEY("--version", FUSE2FS_VERSION),
3669 FUSE_OPT_KEY("-h", FUSE2FS_HELP),
3670 FUSE_OPT_KEY("--help", FUSE2FS_HELP),
3671 FUSE_OPT_KEY("--helpfull", FUSE2FS_HELPFULL),
3676 static int fuse2fs_opt_proc(void *data, const char *arg,
3677 int key, struct fuse_args *outargs)
3679 struct fuse2fs *ff = data;
3682 case FUSE_OPT_KEY_NONOPT:
3684 ff->device = strdup(arg);
3689 case FUSE2FS_HELPFULL:
3691 "usage: %s device/image mountpoint [options]\n"
3693 "general options:\n"
3694 " -o opt,[opt...] mount options\n"
3695 " -h --help print help\n"
3696 " -V --version print version\n"
3698 "fuse2fs options:\n"
3699 " -o ro read-only mount\n"
3700 " -o errors=panic dump core on error\n"
3701 " -o minixdf minix-style df\n"
3702 " -o no_default_opts do not include default fuse options\n"
3703 " -o fuse2fs_debug enable fuse2fs debugging\n"
3706 if (key == FUSE2FS_HELPFULL) {
3707 fuse_opt_add_arg(outargs, "-ho");
3708 fuse_main(outargs->argc, outargs->argv, &fs_ops, NULL);
3710 fprintf(stderr, "Try --helpfull to get a list of "
3711 "all flags, including the FUSE options.\n");
3715 case FUSE2FS_VERSION:
3716 fprintf(stderr, "fuse2fs %s (%s)\n", E2FSPROGS_VERSION,
3718 fuse_opt_add_arg(outargs, "--version");
3719 fuse_main(outargs->argc, outargs->argv, &fs_ops, NULL);
3725 int main(int argc, char *argv[])
3727 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
3728 struct fuse2fs fctx;
3731 char extra_args[BUFSIZ];
3732 int ret = 0, flags = EXT2_FLAG_64BITS | EXT2_FLAG_EXCLUSIVE;
3734 memset(&fctx, 0, sizeof(fctx));
3735 fctx.magic = FUSE2FS_MAGIC;
3737 fuse_opt_parse(&args, &fctx, fuse2fs_opts, fuse2fs_opt_proc);
3738 if (fctx.device == NULL) {
3739 fprintf(stderr, "Missing ext4 device/image\n");
3740 fprintf(stderr, "See '%s -h' for usage\n", argv[0]);
3745 printf("%s", _("Mounting read-only.\n"));
3748 setlocale(LC_MESSAGES, "");
3749 setlocale(LC_CTYPE, "");
3750 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
3751 textdomain(NLS_CAT_NAME);
3752 set_com_err_gettext(gettext);
3754 add_error_table(&et_ext2_error_table);
3756 /* Set up error logging */
3757 logfile = getenv("FUSE2FS_LOGFILE");
3759 fctx.err_fp = fopen(logfile, "a");
3765 fctx.err_fp = stderr;
3767 /* Will we allow users to allocate every last block? */
3768 if (getenv("FUSE2FS_ALLOC_ALL_BLOCKS")) {
3769 printf(_("%s: Allowing users to allocate all blocks. "
3770 "This is dangerous!\n"), fctx.device);
3771 fctx.alloc_all_blocks = 1;
3774 /* Start up the fs (while we still can use stdout) */
3777 flags |= EXT2_FLAG_RW;
3778 err = ext2fs_open2(fctx.device, NULL, flags, 0, 0, unix_io_manager,
3781 printf(_("%s: %s.\n"), fctx.device, error_message(err));
3782 printf(_("Please run e2fsck -fy %s.\n"), fctx.device);
3785 fctx.fs = global_fs;
3786 global_fs->priv_data = &fctx;
3789 if (ext2fs_has_feature_journal_needs_recovery(global_fs->super)) {
3791 printf(_("%s: recovering journal\n"), fctx.device);
3792 err = ext2fs_run_ext3_journal(&global_fs);
3794 printf(_("%s: %s.\n"), fctx.device,
3795 error_message(err));
3796 printf(_("Please run e2fsck -fy %s.\n"),
3800 ext2fs_clear_feature_journal_needs_recovery(global_fs->super);
3801 ext2fs_mark_super_dirty(global_fs);
3803 printf("%s", _("Journal needs recovery; running "
3804 "`e2fsck -E journal_only' is required.\n"));
3810 if (ext2fs_has_feature_journal(global_fs->super))
3811 printf(_("%s: Writing to the journal is not supported.\n"),
3813 err = ext2fs_read_inode_bitmap(global_fs);
3815 translate_error(global_fs, 0, err);
3818 err = ext2fs_read_block_bitmap(global_fs);
3820 translate_error(global_fs, 0, err);
3825 if (!(global_fs->super->s_state & EXT2_VALID_FS))
3826 printf("%s", _("Warning: Mounting unchecked fs, running e2fsck "
3827 "is recommended.\n"));
3828 if (global_fs->super->s_max_mnt_count > 0 &&
3829 global_fs->super->s_mnt_count >= global_fs->super->s_max_mnt_count)
3830 printf("%s", _("Warning: Maximal mount count reached, running "
3831 "e2fsck is recommended.\n"));
3832 if (global_fs->super->s_checkinterval > 0 &&
3833 (time_t) (global_fs->super->s_lastcheck +
3834 global_fs->super->s_checkinterval) <= time(0))
3835 printf("%s", _("Warning: Check time reached; running e2fsck "
3836 "is recommended.\n"));
3837 if (global_fs->super->s_last_orphan)
3839 _("Orphans detected; running e2fsck is recommended.\n"));
3841 if (global_fs->super->s_state & EXT2_ERROR_FS) {
3843 _("Errors detected; running e2fsck is required.\n"));
3847 /* Initialize generation counter */
3848 get_random_bytes(&fctx.next_generation, sizeof(unsigned int));
3850 /* Set up default fuse parameters */
3851 snprintf(extra_args, BUFSIZ, "-okernel_cache,subtype=ext4,use_ino,"
3852 "fsname=%s,attr_timeout=0" FUSE_PLATFORM_OPTS,
3854 if (fctx.no_default_opts == 0)
3855 fuse_opt_add_arg(&args, extra_args);
3860 printf("fuse arguments:");
3861 for (i = 0; i < args.argc; i++)
3862 printf(" '%s'", args.argv[i]);
3866 pthread_mutex_init(&fctx.bfl, NULL);
3867 fuse_main(args.argc, args.argv, &fs_ops, &fctx);
3868 pthread_mutex_destroy(&fctx.bfl);
3872 err = ext2fs_close(global_fs);
3874 com_err(argv[0], err, "while closing fs");
3881 static int __translate_error(ext2_filsys fs, errcode_t err, ext2_ino_t ino,
3882 const char *file, int line)
3884 struct timespec now;
3886 struct fuse2fs *ff = fs->priv_data;
3889 /* Translate ext2 error to unix error code */
3890 if (err < EXT2_ET_BASE)
3891 goto no_translation;
3893 case EXT2_ET_NO_MEMORY:
3894 case EXT2_ET_TDB_ERR_OOM:
3897 case EXT2_ET_INVALID_ARGUMENT:
3898 case EXT2_ET_LLSEEK_FAILED:
3901 case EXT2_ET_NO_DIRECTORY:
3904 case EXT2_ET_FILE_NOT_FOUND:
3907 case EXT2_ET_DIR_NO_SPACE:
3910 case EXT2_ET_TOOSMALL:
3911 case EXT2_ET_BLOCK_ALLOC_FAIL:
3912 case EXT2_ET_INODE_ALLOC_FAIL:
3913 case EXT2_ET_EA_NO_SPACE:
3916 case EXT2_ET_SYMLINK_LOOP:
3919 case EXT2_ET_FILE_TOO_BIG:
3922 case EXT2_ET_TDB_ERR_EXISTS:
3923 case EXT2_ET_FILE_EXISTS:
3926 case EXT2_ET_MMP_FAILED:
3927 case EXT2_ET_MMP_FSCK_ON:
3930 case EXT2_ET_EA_KEY_NOT_FOUND:
3937 /* Sometimes fuse returns a garbage file handle pointer to us... */
3938 case EXT2_ET_MAGIC_EXT2_FILE:
3941 case EXT2_ET_UNIMPLEMENTED:
3955 fprintf(ff->err_fp, "FUSE2FS (%s): %s (inode #%d) at %s:%d.\n",
3956 fs->device_name ? fs->device_name : "???",
3957 error_message(err), ino, file, line);
3959 fprintf(ff->err_fp, "FUSE2FS (%s): %s at %s:%d.\n",
3960 fs->device_name ? fs->device_name : "???",
3961 error_message(err), file, line);
3964 /* Make a note in the error log */
3966 fs->super->s_last_error_time = now.tv_sec;
3967 fs->super->s_last_error_ino = ino;
3968 fs->super->s_last_error_line = line;
3969 fs->super->s_last_error_block = err; /* Yeah... */
3970 strncpy((char *)fs->super->s_last_error_func, file,
3971 sizeof(fs->super->s_last_error_func));
3972 if (fs->super->s_first_error_time == 0) {
3973 fs->super->s_first_error_time = now.tv_sec;
3974 fs->super->s_first_error_ino = ino;
3975 fs->super->s_first_error_line = line;
3976 fs->super->s_first_error_block = err;
3977 strncpy((char *)fs->super->s_first_error_func, file,
3978 sizeof(fs->super->s_first_error_func));
3981 fs->super->s_error_count++;
3982 ext2fs_mark_super_dirty(fs);
3984 if (ff->panic_on_error)