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
17 # include <linux/fs.h>
18 # include <linux/falloc.h>
19 # include <linux/xattr.h>
21 #ifdef HAVE_SYS_XATTR_H
22 #include <sys/xattr.h>
24 #include <sys/ioctl.h>
27 #define FUSE_DARWIN_ENABLE_EXTENSIONS 0
28 #ifdef __SET_FOB_FOR_FUSE
29 # error Do not set magic value __SET_FOB_FOR_FUSE!!!!
31 #ifndef _FILE_OFFSET_BITS
33 * Old versions of libfuse (e.g. Debian 2.9.9 package) required that the build
34 * system set _FILE_OFFSET_BITS explicitly, even if doing so isn't required to
35 * get a 64-bit off_t. AC_SYS_LARGEFILE doesn't set any _FILE_OFFSET_BITS if
36 * it's not required (such as on aarch64), so we must inject it here.
38 # define __SET_FOB_FOR_FUSE
39 # define _FILE_OFFSET_BITS 64
40 #endif /* _FILE_OFFSET_BITS */
42 #ifdef __SET_FOB_FOR_FUSE
43 # undef _FILE_OFFSET_BITS
44 #endif /* __SET_FOB_FOR_FUSE */
46 #include "ext2fs/ext2fs.h"
47 #include "ext2fs/ext2_fs.h"
48 #include "ext2fs/ext2fsP.h"
49 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
50 # define FUSE_PLATFORM_OPTS ""
53 # define FUSE_PLATFORM_OPTS ",use_ino,big_writes"
55 # define FUSE_PLATFORM_OPTS ",use_ino"
59 #include "../version.h"
60 #include "uuid/uuid.h"
66 #define _(a) (gettext(a))
68 #define N_(a) gettext_noop(a)
72 #define P_(singular, plural, n) (ngettext(singular, plural, n))
74 #define NLS_CAT_NAME "e2fsprogs"
77 #define LOCALEDIR "/usr/share/locale"
82 #define P_(singular, plural, n) ((n) == 1 ? (singular) : (plural))
85 #ifndef XATTR_NAME_POSIX_ACL_DEFAULT
86 #define XATTR_NAME_POSIX_ACL_DEFAULT "posix_acl_default"
88 #ifndef XATTR_SECURITY_PREFIX
89 #define XATTR_SECURITY_PREFIX "security."
90 #define XATTR_SECURITY_PREFIX_LEN (sizeof (XATTR_SECURITY_PREFIX) - 1)
94 * Linux and MacOS implement the setxattr(2) interface, which defines
95 * XATTR_CREATE and XATTR_REPLACE. However, FreeBSD uses
96 * extattr_set_file(2), which does not have a flags or options
97 * parameter, and does not define XATTR_CREATE and XATTR_REPLACE.
100 #define XATTR_CREATE 0
103 #ifndef XATTR_REPLACE
104 #define XATTR_REPLACE 0
107 #if !defined(EUCLEAN)
108 #if !defined(EBADMSG)
109 #define EUCLEAN EBADMSG
110 #elif !defined(EPROTO)
111 #define EUCLEAN EPROTO
115 #endif /* !defined(EUCLEAN) */
117 #if !defined(ENODATA)
119 #define ENODATA ENOATTR
121 #define ENODATA ENOENT
123 #endif /* !defined(ENODATA) */
125 static ext2_filsys global_fs
; /* Try not to use this directly */
127 static inline uint64_t round_up(uint64_t b
, unsigned int align
)
139 static inline uint64_t round_down(uint64_t b
, unsigned int align
)
149 #define dbg_printf(fuse2fs, format, ...) \
150 while ((fuse2fs)->debug) { \
151 printf("FUSE2FS (%s): " format, (fuse2fs)->shortdev, ##__VA_ARGS__); \
156 #define log_printf(fuse2fs, format, ...) \
158 printf("FUSE2FS (%s): " format, (fuse2fs)->shortdev, ##__VA_ARGS__); \
162 #define err_printf(fuse2fs, format, ...) \
164 fprintf(stderr, "FUSE2FS (%s): " format, (fuse2fs)->shortdev, ##__VA_ARGS__); \
168 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
171 # define SUPPORT_I_FLAGS
176 #ifdef FALLOC_FL_KEEP_SIZE
177 # define FL_KEEP_SIZE_FLAG FALLOC_FL_KEEP_SIZE
178 # define SUPPORT_FALLOCATE
180 # define FL_KEEP_SIZE_FLAG (0)
183 #ifdef FALLOC_FL_PUNCH_HOLE
184 # define FL_PUNCH_HOLE_FLAG FALLOC_FL_PUNCH_HOLE
186 # define FL_PUNCH_HOLE_FLAG (0)
189 #ifdef FALLOC_FL_ZERO_RANGE
190 # define FL_ZERO_RANGE_FLAG FALLOC_FL_ZERO_RANGE
192 # define FL_ZERO_RANGE_FLAG (0)
195 errcode_t
ext2fs_run_ext3_journal(ext2_filsys
*fs
);
197 #ifdef CONFIG_JBD_DEBUG /* Enabled by configure --enable-jbd-debug */
198 int journal_enable_debug
= -1;
202 * ext2_file_t contains a struct inode, so we can't leave files open.
203 * Use this as a proxy instead.
205 #define FUSE2FS_FILE_MAGIC (0xEF53DEAFUL)
206 struct fuse2fs_file_handle
{
212 /* Main program context */
213 #define FUSE2FS_MAGIC (0xEF53DEADUL)
222 uint8_t no_default_opts
;
223 uint8_t panic_on_error
;
226 uint8_t alloc_all_blocks
;
234 unsigned int blockmask
;
235 unsigned long offset
;
236 unsigned int next_generation
;
237 unsigned long long cache_size
;
241 #define FUSE2FS_CHECK_MAGIC(fs, ptr, num) do {if ((ptr)->magic != (num)) \
242 return translate_error((fs), 0, EXT2_ET_FILESYSTEM_CORRUPTED); \
245 #define FUSE2FS_CHECK_CONTEXT(ptr) do {if ((ptr)->magic != FUSE2FS_MAGIC) \
246 return translate_error(global_fs, 0, EXT2_ET_FILESYSTEM_CORRUPTED); \
249 static int __translate_error(ext2_filsys fs
, ext2_ino_t ino
, errcode_t err
,
250 const char *file
, int line
);
251 #define translate_error(fs, ino, err) __translate_error((fs), (ino), (err), \
263 static inline int u_log2(unsigned int arg
)
275 static inline blk64_t
FUSE2FS_B_TO_FSBT(const struct fuse2fs
*ff
, off_t pos
)
277 return pos
>> ff
->blocklog
;
280 static inline blk64_t
FUSE2FS_B_TO_FSB(const struct fuse2fs
*ff
, off_t pos
)
282 return (pos
+ ff
->blockmask
) >> ff
->blocklog
;
285 static inline unsigned int FUSE2FS_OFF_IN_FSB(const struct fuse2fs
*ff
,
288 return pos
& ff
->blockmask
;
291 static inline off_t
FUSE2FS_FSB_TO_B(const struct fuse2fs
*ff
, blk64_t bno
)
293 return bno
<< ff
->blocklog
;
296 #define EXT4_EPOCH_BITS 2
297 #define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1)
298 #define EXT4_NSEC_MASK (~0UL << EXT4_EPOCH_BITS)
301 * Extended fields will fit into an inode if the filesystem was formatted
302 * with large inodes (-I 256 or larger) and there are not currently any EAs
303 * consuming all of the available space. For new inodes we always reserve
304 * enough space for the kernel's known extended fields, but for inodes
305 * created with an old kernel this might not have been the case. None of
306 * the extended inode fields is critical for correct filesystem operation.
307 * This macro checks if a certain field fits in the inode. Note that
308 * inode-size = GOOD_OLD_INODE_SIZE + i_extra_isize
310 #define EXT4_FITS_IN_INODE(ext4_inode, field) \
311 ((offsetof(typeof(*ext4_inode), field) + \
312 sizeof((ext4_inode)->field)) \
313 <= ((size_t) EXT2_GOOD_OLD_INODE_SIZE + \
314 (ext4_inode)->i_extra_isize)) \
316 static inline __u32 ext4_encode_extra_time(const struct timespec *time)
318 __u32 extra
= sizeof(time
->tv_sec
) > 4 ?
319 ((time
->tv_sec
- (__s32
)time
->tv_sec
) >> 32) &
321 return extra
| (time
->tv_nsec
<< EXT4_EPOCH_BITS
);
324 static inline void ext4_decode_extra_time(struct timespec
*time
, __u32 extra
)
326 if (sizeof(time
->tv_sec
) > 4 && (extra
& EXT4_EPOCH_MASK
)) {
327 __u64 extra_bits
= extra
& EXT4_EPOCH_MASK
;
329 * Prior to kernel 3.14?, we had a broken decode function,
330 * wherein we effectively did this:
331 * if (extra_bits == 3)
334 time
->tv_sec
+= extra_bits
<< 32;
336 time
->tv_nsec
= ((extra
) & EXT4_NSEC_MASK
) >> EXT4_EPOCH_BITS
;
339 #define EXT4_CLAMP_TIMESTAMP(xtime, timespec, raw_inode) \
341 if ((timespec)->tv_sec < EXT4_TIMESTAMP_MIN) \
342 (timespec)->tv_sec = EXT4_TIMESTAMP_MIN; \
343 if ((timespec)->tv_sec < EXT4_TIMESTAMP_MIN) \
344 (timespec)->tv_sec = EXT4_TIMESTAMP_MIN; \
346 if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) { \
347 if ((timespec)->tv_sec > EXT4_EXTRA_TIMESTAMP_MAX) \
348 (timespec)->tv_sec = EXT4_EXTRA_TIMESTAMP_MAX; \
350 if ((timespec)->tv_sec > EXT4_NON_EXTRA_TIMESTAMP_MAX) \
351 (timespec)->tv_sec = EXT4_NON_EXTRA_TIMESTAMP_MAX; \
355 #define EXT4_INODE_SET_XTIME(xtime, timespec, raw_inode) \
357 typeof(*(timespec)) _ts = *(timespec); \
359 EXT4_CLAMP_TIMESTAMP(xtime, &_ts, raw_inode); \
360 (raw_inode)->xtime = _ts.tv_sec; \
361 if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \
362 (raw_inode)->xtime ## _extra = \
363 ext4_encode_extra_time(&_ts); \
366 #define EXT4_EINODE_SET_XTIME(xtime, timespec, raw_inode) \
368 typeof(*(timespec)) _ts = *(timespec); \
370 EXT4_CLAMP_TIMESTAMP(xtime, &_ts, raw_inode); \
371 if (EXT4_FITS_IN_INODE(raw_inode, xtime)) \
372 (raw_inode)->xtime = _ts.tv_sec; \
373 if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \
374 (raw_inode)->xtime ## _extra = \
375 ext4_encode_extra_time(&_ts); \
378 #define EXT4_INODE_GET_XTIME(xtime, timespec, raw_inode) \
380 (timespec)->tv_sec = (signed)((raw_inode)->xtime); \
381 if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \
382 ext4_decode_extra_time((timespec), \
383 (raw_inode)->xtime ## _extra); \
385 (timespec)->tv_nsec = 0; \
388 #define EXT4_EINODE_GET_XTIME(xtime, timespec, raw_inode) \
390 if (EXT4_FITS_IN_INODE(raw_inode, xtime)) \
391 (timespec)->tv_sec = \
392 (signed)((raw_inode)->xtime); \
393 if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \
394 ext4_decode_extra_time((timespec), \
395 raw_inode->xtime ## _extra); \
397 (timespec)->tv_nsec = 0; \
400 static inline errcode_t
fuse2fs_read_inode(ext2_filsys fs
, ext2_ino_t ino
,
401 struct ext2_inode_large
*inode
)
403 memset(inode
, 0, sizeof(*inode
));
404 return ext2fs_read_inode_full(fs
, ino
, EXT2_INODE(inode
),
408 static inline errcode_t
fuse2fs_write_inode(ext2_filsys fs
, ext2_ino_t ino
,
409 struct ext2_inode_large
*inode
)
411 return ext2fs_write_inode_full(fs
, ino
, EXT2_INODE(inode
),
415 static void get_now(struct timespec
*now
)
417 #ifdef CLOCK_REALTIME
418 if (!clock_gettime(CLOCK_REALTIME
, now
))
422 now
->tv_sec
= time(NULL
);
426 static void increment_version(struct ext2_inode_large
*inode
)
430 ver
= inode
->osd1
.linux1
.l_i_version
;
431 if (EXT4_FITS_IN_INODE(inode
, i_version_hi
))
432 ver
|= (__u64
)inode
->i_version_hi
<< 32;
434 inode
->osd1
.linux1
.l_i_version
= ver
;
435 if (EXT4_FITS_IN_INODE(inode
, i_version_hi
))
436 inode
->i_version_hi
= ver
>> 32;
439 static void init_times(struct ext2_inode_large
*inode
)
444 EXT4_INODE_SET_XTIME(i_atime
, &now
, inode
);
445 EXT4_INODE_SET_XTIME(i_ctime
, &now
, inode
);
446 EXT4_INODE_SET_XTIME(i_mtime
, &now
, inode
);
447 EXT4_EINODE_SET_XTIME(i_crtime
, &now
, inode
);
448 increment_version(inode
);
451 static int update_ctime(ext2_filsys fs
, ext2_ino_t ino
,
452 struct ext2_inode_large
*pinode
)
456 struct ext2_inode_large inode
;
460 /* If user already has a inode buffer, just update that */
462 increment_version(pinode
);
463 EXT4_INODE_SET_XTIME(i_ctime
, &now
, pinode
);
467 /* Otherwise we have to read-modify-write the inode */
468 err
= fuse2fs_read_inode(fs
, ino
, &inode
);
470 return translate_error(fs
, ino
, err
);
472 increment_version(&inode
);
473 EXT4_INODE_SET_XTIME(i_ctime
, &now
, &inode
);
475 err
= fuse2fs_write_inode(fs
, ino
, &inode
);
477 return translate_error(fs
, ino
, err
);
482 static int update_atime(ext2_filsys fs
, ext2_ino_t ino
)
485 struct ext2_inode_large inode
, *pinode
;
486 struct timespec atime
, mtime
, now
;
487 double datime
, dmtime
, dnow
;
489 if (!(fs
->flags
& EXT2_FLAG_RW
))
491 err
= fuse2fs_read_inode(fs
, ino
, &inode
);
493 return translate_error(fs
, ino
, err
);
496 EXT4_INODE_GET_XTIME(i_atime
, &atime
, pinode
);
497 EXT4_INODE_GET_XTIME(i_mtime
, &mtime
, pinode
);
500 datime
= atime
.tv_sec
+ ((double)atime
.tv_nsec
/ 1000000000);
501 dmtime
= mtime
.tv_sec
+ ((double)mtime
.tv_nsec
/ 1000000000);
502 dnow
= now
.tv_sec
+ ((double)now
.tv_nsec
/ 1000000000);
505 * If atime is newer than mtime and atime hasn't been updated in thirty
506 * seconds, skip the atime update. Same idea as Linux "relatime". Use
507 * doubles to account for nanosecond resolution.
509 if (datime
>= dmtime
&& datime
>= dnow
- 30)
511 EXT4_INODE_SET_XTIME(i_atime
, &now
, &inode
);
513 err
= fuse2fs_write_inode(fs
, ino
, &inode
);
515 return translate_error(fs
, ino
, err
);
520 static int update_mtime(ext2_filsys fs
, ext2_ino_t ino
,
521 struct ext2_inode_large
*pinode
)
524 struct ext2_inode_large inode
;
529 EXT4_INODE_SET_XTIME(i_mtime
, &now
, pinode
);
530 EXT4_INODE_SET_XTIME(i_ctime
, &now
, pinode
);
531 increment_version(pinode
);
535 err
= fuse2fs_read_inode(fs
, ino
, &inode
);
537 return translate_error(fs
, ino
, err
);
540 EXT4_INODE_SET_XTIME(i_mtime
, &now
, &inode
);
541 EXT4_INODE_SET_XTIME(i_ctime
, &now
, &inode
);
542 increment_version(&inode
);
544 err
= fuse2fs_write_inode(fs
, ino
, &inode
);
546 return translate_error(fs
, ino
, err
);
551 static int ext2_file_type(unsigned int mode
)
553 if (LINUX_S_ISREG(mode
))
554 return EXT2_FT_REG_FILE
;
556 if (LINUX_S_ISDIR(mode
))
559 if (LINUX_S_ISCHR(mode
))
560 return EXT2_FT_CHRDEV
;
562 if (LINUX_S_ISBLK(mode
))
563 return EXT2_FT_BLKDEV
;
565 if (LINUX_S_ISLNK(mode
))
566 return EXT2_FT_SYMLINK
;
568 if (LINUX_S_ISFIFO(mode
))
571 if (LINUX_S_ISSOCK(mode
))
577 static int fs_can_allocate(struct fuse2fs
*ff
, blk64_t num
)
579 ext2_filsys fs
= ff
->fs
;
582 dbg_printf(ff
, "%s: Asking for %llu; alloc_all=%d total=%llu free=%llu "
583 "rsvd=%llu\n", __func__
, num
, ff
->alloc_all_blocks
,
584 ext2fs_blocks_count(fs
->super
),
585 ext2fs_free_blocks_count(fs
->super
),
586 ext2fs_r_blocks_count(fs
->super
));
587 if (num
> ext2fs_blocks_count(fs
->super
))
590 if (ff
->alloc_all_blocks
)
594 * Different meaning for r_blocks -- libext2fs has bugs where the FS
595 * can get corrupted if it totally runs out of blocks. Avoid this
596 * by refusing to allocate any of the reserve blocks to anybody.
598 reserved
= ext2fs_r_blocks_count(fs
->super
);
600 reserved
= ext2fs_blocks_count(fs
->super
) / 10;
601 return ext2fs_free_blocks_count(fs
->super
) > reserved
+ num
;
604 static int fs_writeable(ext2_filsys fs
)
606 return (fs
->flags
& EXT2_FLAG_RW
) && (fs
->super
->s_error_count
== 0);
609 static inline int is_superuser(struct fuse2fs
*ff
, struct fuse_context
*ctxt
)
613 return ctxt
->uid
== 0;
616 static inline int want_check_owner(struct fuse2fs
*ff
,
617 struct fuse_context
*ctxt
)
620 * The kernel is responsible for access control, so we allow anything
621 * that the superuser can do.
625 return !is_superuser(ff
, ctxt
);
628 /* Test for append permission */
631 static int check_iflags_access(struct fuse2fs
*ff
, ext2_ino_t ino
,
632 const struct ext2_inode
*inode
, int mask
)
634 ext2_filsys fs
= ff
->fs
;
636 EXT2FS_BUILD_BUG_ON((A_OK
& (R_OK
| W_OK
| X_OK
| F_OK
)) != 0);
638 /* no writing or metadata changes to read-only or broken fs */
639 if ((mask
& (W_OK
| A_OK
)) && !fs_writeable(fs
))
642 dbg_printf(ff
, "access ino=%d mask=e%s%s%s%s iflags=0x%x\n",
644 (mask
& R_OK
? "r" : ""),
645 (mask
& W_OK
? "w" : ""),
646 (mask
& X_OK
? "x" : ""),
647 (mask
& A_OK
? "a" : ""),
652 (inode
->i_flags
& EXT2_IMMUTABLE_FL
))
655 /* is append-only? */
656 if ((inode
->i_flags
& EXT2_APPEND_FL
) && (mask
& W_OK
) && !(mask
& A_OK
))
662 static int check_inum_access(struct fuse2fs
*ff
, ext2_ino_t ino
, int mask
)
664 struct fuse_context
*ctxt
= fuse_get_context();
665 ext2_filsys fs
= ff
->fs
;
666 struct ext2_inode inode
;
671 /* no writing to read-only or broken fs */
672 if ((mask
& (W_OK
| A_OK
)) && !fs_writeable(fs
))
675 err
= ext2fs_read_inode(fs
, ino
, &inode
);
677 return translate_error(fs
, ino
, err
);
678 perms
= inode
.i_mode
& 0777;
680 dbg_printf(ff
, "access ino=%d mask=e%s%s%s%s perms=0%o iflags=0x%x "
681 "fuid=%d fgid=%d uid=%d gid=%d\n", ino
,
682 (mask
& R_OK
? "r" : ""),
683 (mask
& W_OK
? "w" : ""),
684 (mask
& X_OK
? "x" : ""),
685 (mask
& A_OK
? "a" : ""),
686 perms
, inode
.i_flags
,
687 inode_uid(inode
), inode_gid(inode
),
688 ctxt
->uid
, ctxt
->gid
);
690 /* existence check */
694 ret
= check_iflags_access(ff
, ino
, &inode
, mask
);
698 /* If kernel is responsible for mode and acl checks, we're done. */
702 /* Figure out what root's allowed to do */
703 if (is_superuser(ff
, ctxt
)) {
704 /* Non-file access always ok */
705 if (!LINUX_S_ISREG(inode
.i_mode
))
708 /* R/W access to a file always ok */
712 /* X access to a file ok if a user/group/other can X */
716 /* Trying to execute a file that's not executable. BZZT! */
720 /* Remove the O_APPEND flag before testing permissions */
723 /* allow owner, if perms match */
724 if (inode_uid(inode
) == ctxt
->uid
) {
725 if ((mask
& (perms
>> 6)) == mask
)
730 /* allow group, if perms match */
731 if (inode_gid(inode
) == ctxt
->gid
) {
732 if ((mask
& (perms
>> 3)) == mask
)
737 /* otherwise check other */
738 if ((mask
& perms
) == mask
)
743 static void op_destroy(void *p
EXT2FS_ATTR((unused
)))
745 struct fuse_context
*ctxt
= fuse_get_context();
746 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
750 if (ff
->magic
!= FUSE2FS_MAGIC
) {
751 translate_error(global_fs
, 0, EXT2_ET_BAD_MAGIC
);
755 pthread_mutex_lock(&ff
->bfl
);
758 dbg_printf(ff
, "%s: dev=%s\n", __func__
, fs
->device_name
);
759 if (fs
->flags
& EXT2_FLAG_RW
) {
760 fs
->super
->s_state
|= EXT2_VALID_FS
;
761 if (fs
->super
->s_error_count
)
762 fs
->super
->s_state
|= EXT2_ERROR_FS
;
763 ext2fs_mark_super_dirty(fs
);
764 err
= ext2fs_set_gdt_csum(fs
);
766 translate_error(fs
, 0, err
);
768 err
= ext2fs_flush2(fs
, 0);
770 translate_error(fs
, 0, err
);
773 if (ff
->debug
&& fs
->io
->manager
->get_stats
) {
774 io_stats stats
= NULL
;
776 fs
->io
->manager
->get_stats(fs
->io
, &stats
);
777 dbg_printf(ff
, "read: %lluk\n", stats
->bytes_read
>> 10);
778 dbg_printf(ff
, "write: %lluk\n", stats
->bytes_written
>> 10);
779 dbg_printf(ff
, "hits: %llu\n", stats
->cache_hits
);
780 dbg_printf(ff
, "misses: %llu\n", stats
->cache_misses
);
781 dbg_printf(ff
, "hit_ratio: %.1f%%\n",
782 (100.0 * stats
->cache_hits
) /
783 (stats
->cache_hits
+ stats
->cache_misses
));
787 char uuid
[UUID_STR_SIZE
];
789 uuid_unparse(fs
->super
->s_uuid
, uuid
);
790 log_printf(ff
, "%s %s.\n", _("unmounting filesystem"), uuid
);
793 pthread_mutex_unlock(&ff
->bfl
);
796 /* Reopen @stream with @fileno */
797 static int fuse2fs_freopen_stream(const char *path
, int fileno
, FILE *stream
)
804 ret
= snprintf(_fdpath
, sizeof(_fdpath
), "/dev/fd/%d", fileno
);
805 if (ret
>= sizeof(_fdpath
))
811 * C23 defines std{out,err} as an expression of type FILE* that need
812 * not be an lvalue. What this means is that we can't just assign to
813 * stdout: we have to use freopen, which takes a path.
815 * There's no guarantee that the OS provides a /dev/fd/X alias for open
816 * file descriptors, so if that fails, fall back to the original log
817 * file path. We'd rather not do a path-based reopen because that
818 * exposes us to rename race attacks.
820 fp
= freopen(fdpath
, "a", stream
);
821 if (!fp
&& errno
== ENOENT
&& fdpath
== _fdpath
)
822 fp
= freopen(path
, "a", stream
);
831 /* Redirect stdout/stderr to a file, or return a mount-compatible error. */
832 static int fuse2fs_capture_output(struct fuse2fs
*ff
, const char *path
)
838 * First, open the log file path with system calls so that we can
839 * redirect the stdout/stderr file numbers (typically 1 and 2) to our
840 * logfile descriptor. We'd like to avoid allocating extra file
841 * objects in the kernel if we can because pos will be the same between
845 fd
= open(path
, O_WRONLY
| O_CREAT
| O_APPEND
, 0600);
852 * Save the newly opened fd in case we have to do this again in
858 ret
= dup2(ff
->logfd
, STDOUT_FILENO
);
864 ret
= dup2(ff
->logfd
, STDERR_FILENO
);
871 * Now that we've changed STD{OUT,ERR}_FILENO to be the log file, use
872 * freopen to make sure that std{out,err} (the C library abstractions)
873 * point to the STDXXX_FILENO because any of our library dependencies
874 * might decide to printf to one of those streams and we want to
875 * capture all output in the log.
877 ret
= fuse2fs_freopen_stream(path
, STDOUT_FILENO
, stdout
);
880 ret
= fuse2fs_freopen_stream(path
, STDERR_FILENO
, stderr
);
887 /* Set up debug and error logging files */
888 static int fuse2fs_setup_logging(struct fuse2fs
*ff
)
890 char *logfile
= getenv("FUSE2FS_LOGFILE");
892 return fuse2fs_capture_output(ff
, logfile
);
894 /* in kernel mode, try to log errors to the kernel log */
896 fuse2fs_capture_output(ff
, "/dev/ttyprintk");
901 static void *op_init(struct fuse_conn_info
*conn
902 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
903 , struct fuse_config
*cfg
EXT2FS_ATTR((unused
))
907 struct fuse_context
*ctxt
= fuse_get_context();
908 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
912 if (ff
->magic
!= FUSE2FS_MAGIC
) {
913 translate_error(global_fs
, 0, EXT2_ET_BAD_MAGIC
);
918 * Configure logging a second time, because libfuse might have
919 * redirected std{out,err} as part of daemonization. If this fails,
920 * give up and move on.
922 fuse2fs_setup_logging(ff
);
928 dbg_printf(ff
, "%s: dev=%s\n", __func__
, fs
->device_name
);
929 #ifdef FUSE_CAP_IOCTL_DIR
930 conn
->want
|= FUSE_CAP_IOCTL_DIR
;
932 #ifdef FUSE_CAP_POSIX_ACL
934 conn
->want
|= FUSE_CAP_POSIX_ACL
;
936 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
942 if (fs
->flags
& EXT2_FLAG_RW
) {
943 fs
->super
->s_mnt_count
++;
944 ext2fs_set_tstamp(fs
->super
, s_mtime
, time(NULL
));
945 fs
->super
->s_state
&= ~EXT2_VALID_FS
;
946 ext2fs_mark_super_dirty(fs
);
947 err
= ext2fs_flush2(fs
, 0);
949 translate_error(fs
, 0, err
);
953 char uuid
[UUID_STR_SIZE
];
955 uuid_unparse(fs
->super
->s_uuid
, uuid
);
956 log_printf(ff
, "%s %s.\n", _("mounted filesystem"), uuid
);
961 static int stat_inode(ext2_filsys fs
, ext2_ino_t ino
, struct stat
*statbuf
)
963 struct ext2_inode_large inode
;
969 err
= fuse2fs_read_inode(fs
, ino
, &inode
);
971 return translate_error(fs
, ino
, err
);
973 memcpy(&fakedev
, fs
->super
->s_uuid
, sizeof(fakedev
));
974 statbuf
->st_dev
= fakedev
;
975 statbuf
->st_ino
= ino
;
976 statbuf
->st_mode
= inode
.i_mode
;
977 statbuf
->st_nlink
= inode
.i_links_count
;
978 statbuf
->st_uid
= inode_uid(inode
);
979 statbuf
->st_gid
= inode_gid(inode
);
980 statbuf
->st_size
= EXT2_I_SIZE(&inode
);
981 statbuf
->st_blksize
= fs
->blocksize
;
982 statbuf
->st_blocks
= ext2fs_get_stat_i_blocks(fs
,
984 EXT4_INODE_GET_XTIME(i_atime
, &tv
, &inode
);
985 #if HAVE_STRUCT_STAT_ST_ATIM
986 statbuf
->st_atim
= tv
;
988 statbuf
->st_atime
= tv
.tv_sec
;
990 EXT4_INODE_GET_XTIME(i_mtime
, &tv
, &inode
);
991 #if HAVE_STRUCT_STAT_ST_ATIM
992 statbuf
->st_mtim
= tv
;
994 statbuf
->st_mtime
= tv
.tv_sec
;
996 EXT4_INODE_GET_XTIME(i_ctime
, &tv
, &inode
);
997 #if HAVE_STRUCT_STAT_ST_ATIM
998 statbuf
->st_ctim
= tv
;
1000 statbuf
->st_ctime
= tv
.tv_sec
;
1002 if (LINUX_S_ISCHR(inode
.i_mode
) ||
1003 LINUX_S_ISBLK(inode
.i_mode
)) {
1004 if (inode
.i_block
[0])
1005 statbuf
->st_rdev
= inode
.i_block
[0];
1007 statbuf
->st_rdev
= inode
.i_block
[1];
1013 static int op_getattr(const char *path
, struct stat
*statbuf
1014 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
1015 , struct fuse_file_info
*fi
EXT2FS_ATTR((unused
))
1019 struct fuse_context
*ctxt
= fuse_get_context();
1020 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
1026 FUSE2FS_CHECK_CONTEXT(ff
);
1028 dbg_printf(ff
, "%s: path=%s\n", __func__
, path
);
1029 pthread_mutex_lock(&ff
->bfl
);
1030 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
1032 ret
= translate_error(fs
, 0, err
);
1035 ret
= stat_inode(fs
, ino
, statbuf
);
1037 pthread_mutex_unlock(&ff
->bfl
);
1041 static int op_readlink(const char *path
, char *buf
, size_t len
)
1043 struct fuse_context
*ctxt
= fuse_get_context();
1044 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
1048 struct ext2_inode inode
;
1053 FUSE2FS_CHECK_CONTEXT(ff
);
1055 dbg_printf(ff
, "%s: path=%s\n", __func__
, path
);
1056 pthread_mutex_lock(&ff
->bfl
);
1057 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
1058 if (err
|| ino
== 0) {
1059 ret
= translate_error(fs
, 0, err
);
1063 err
= ext2fs_read_inode(fs
, ino
, &inode
);
1065 ret
= translate_error(fs
, ino
, err
);
1069 if (!LINUX_S_ISLNK(inode
.i_mode
)) {
1075 if (inode
.i_size
< len
)
1077 if (ext2fs_is_fast_symlink(&inode
))
1078 memcpy(buf
, (char *)inode
.i_block
, len
);
1080 /* big/inline symlink */
1082 err
= ext2fs_file_open(fs
, ino
, 0, &file
);
1084 ret
= translate_error(fs
, ino
, err
);
1088 err
= ext2fs_file_read(file
, buf
, len
, &got
);
1089 if (err
|| got
!= len
) {
1090 ext2fs_file_close(file
);
1091 ret
= translate_error(fs
, ino
, err
);
1096 err
= ext2fs_file_close(file
);
1100 ret
= translate_error(fs
, ino
, err
);
1106 if (fs_writeable(fs
)) {
1107 ret
= update_atime(fs
, ino
);
1113 pthread_mutex_unlock(&ff
->bfl
);
1117 static int __getxattr(struct fuse2fs
*ff
, ext2_ino_t ino
, const char *name
,
1118 void **value
, size_t *value_len
)
1120 ext2_filsys fs
= ff
->fs
;
1121 struct ext2_xattr_handle
*h
;
1125 err
= ext2fs_xattrs_open(fs
, ino
, &h
);
1127 return translate_error(fs
, ino
, err
);
1129 err
= ext2fs_xattrs_read(h
);
1131 ret
= translate_error(fs
, ino
, err
);
1135 err
= ext2fs_xattr_get(h
, name
, value
, value_len
);
1137 ret
= translate_error(fs
, ino
, err
);
1142 err
= ext2fs_xattrs_close(&h
);
1144 ret
= translate_error(fs
, ino
, err
);
1148 static int __setxattr(struct fuse2fs
*ff
, ext2_ino_t ino
, const char *name
,
1149 void *value
, size_t valuelen
)
1151 ext2_filsys fs
= ff
->fs
;
1152 struct ext2_xattr_handle
*h
;
1156 err
= ext2fs_xattrs_open(fs
, ino
, &h
);
1158 return translate_error(fs
, ino
, err
);
1160 err
= ext2fs_xattrs_read(h
);
1162 ret
= translate_error(fs
, ino
, err
);
1166 err
= ext2fs_xattr_set(h
, name
, value
, valuelen
);
1168 ret
= translate_error(fs
, ino
, err
);
1173 err
= ext2fs_xattrs_close(&h
);
1175 ret
= translate_error(fs
, ino
, err
);
1179 static int propagate_default_acls(struct fuse2fs
*ff
, ext2_ino_t parent
,
1189 ret
= __getxattr(ff
, parent
, XATTR_NAME_POSIX_ACL_DEFAULT
, &def
,
1194 /* no default acl */
1202 ret
= __setxattr(ff
, child
, XATTR_NAME_POSIX_ACL_DEFAULT
, def
, deflen
);
1203 ext2fs_free_mem(&def
);
1207 static inline void fuse2fs_set_uid(struct ext2_inode_large
*inode
, uid_t uid
)
1210 ext2fs_set_i_uid_high(*inode
, uid
>> 16);
1213 static inline void fuse2fs_set_gid(struct ext2_inode_large
*inode
, gid_t gid
)
1216 ext2fs_set_i_gid_high(*inode
, gid
>> 16);
1219 static int fuse2fs_new_child_gid(struct fuse2fs
*ff
, ext2_ino_t parent
,
1220 gid_t
*gid
, int *parent_sgid
)
1222 struct ext2_inode_large inode
;
1223 struct fuse_context
*ctxt
= fuse_get_context();
1226 err
= fuse2fs_read_inode(ff
->fs
, parent
, &inode
);
1228 return translate_error(ff
->fs
, parent
, err
);
1230 if (inode
.i_mode
& S_ISGID
) {
1243 static int op_mknod(const char *path
, mode_t mode
, dev_t dev
)
1245 struct fuse_context
*ctxt
= fuse_get_context();
1246 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
1248 ext2_ino_t parent
, child
;
1253 struct ext2_inode_large inode
;
1257 FUSE2FS_CHECK_CONTEXT(ff
);
1259 dbg_printf(ff
, "%s: path=%s mode=0%o dev=0x%x\n", __func__
, path
, mode
,
1261 temp_path
= strdup(path
);
1266 node_name
= strrchr(temp_path
, '/');
1275 pthread_mutex_lock(&ff
->bfl
);
1276 if (!fs_can_allocate(ff
, 2)) {
1281 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, temp_path
,
1284 ret
= translate_error(fs
, 0, err
);
1288 ret
= check_inum_access(ff
, parent
, A_OK
| W_OK
);
1294 if (LINUX_S_ISCHR(mode
))
1295 filetype
= EXT2_FT_CHRDEV
;
1296 else if (LINUX_S_ISBLK(mode
))
1297 filetype
= EXT2_FT_BLKDEV
;
1298 else if (LINUX_S_ISFIFO(mode
))
1299 filetype
= EXT2_FT_FIFO
;
1300 else if (LINUX_S_ISSOCK(mode
))
1301 filetype
= EXT2_FT_SOCK
;
1307 err
= fuse2fs_new_child_gid(ff
, parent
, &gid
, NULL
);
1311 err
= ext2fs_new_inode(fs
, parent
, mode
, 0, &child
);
1313 ret
= translate_error(fs
, 0, err
);
1317 dbg_printf(ff
, "%s: create ino=%d/name=%s in dir=%d\n", __func__
, child
,
1319 err
= ext2fs_link(fs
, parent
, node_name
, child
,
1320 filetype
| EXT2FS_LINK_EXPAND
);
1322 ret
= translate_error(fs
, parent
, err
);
1326 ret
= update_mtime(fs
, parent
, NULL
);
1330 memset(&inode
, 0, sizeof(inode
));
1331 inode
.i_mode
= mode
;
1334 inode
.i_block
[1] = dev
;
1336 inode
.i_block
[0] = dev
;
1337 inode
.i_links_count
= 1;
1338 inode
.i_extra_isize
= sizeof(struct ext2_inode_large
) -
1339 EXT2_GOOD_OLD_INODE_SIZE
;
1340 fuse2fs_set_uid(&inode
, ctxt
->uid
);
1341 fuse2fs_set_gid(&inode
, gid
);
1343 err
= ext2fs_write_new_inode(fs
, child
, EXT2_INODE(&inode
));
1345 ret
= translate_error(fs
, child
, err
);
1349 inode
.i_generation
= ff
->next_generation
++;
1351 err
= fuse2fs_write_inode(fs
, child
, &inode
);
1353 ret
= translate_error(fs
, child
, err
);
1357 ext2fs_inode_alloc_stats2(fs
, child
, 1, 0);
1359 ret
= propagate_default_acls(ff
, parent
, child
);
1363 pthread_mutex_unlock(&ff
->bfl
);
1369 static int op_mkdir(const char *path
, mode_t mode
)
1371 struct fuse_context
*ctxt
= fuse_get_context();
1372 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
1374 ext2_ino_t parent
, child
;
1378 struct ext2_inode_large inode
;
1385 FUSE2FS_CHECK_CONTEXT(ff
);
1387 dbg_printf(ff
, "%s: path=%s mode=0%o\n", __func__
, path
, mode
);
1388 temp_path
= strdup(path
);
1393 node_name
= strrchr(temp_path
, '/');
1402 pthread_mutex_lock(&ff
->bfl
);
1403 if (!fs_can_allocate(ff
, 1)) {
1408 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, temp_path
,
1411 ret
= translate_error(fs
, 0, err
);
1415 ret
= check_inum_access(ff
, parent
, A_OK
| W_OK
);
1419 err
= fuse2fs_new_child_gid(ff
, parent
, &gid
, &parent_sgid
);
1425 err
= ext2fs_mkdir2(fs
, parent
, 0, 0, EXT2FS_LINK_EXPAND
,
1428 ret
= translate_error(fs
, parent
, err
);
1432 ret
= update_mtime(fs
, parent
, NULL
);
1436 /* Still have to update the uid/gid of the dir */
1437 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, temp_path
,
1440 ret
= translate_error(fs
, 0, err
);
1443 dbg_printf(ff
, "%s: created ino=%d/path=%s in dir=%d\n", __func__
, child
,
1446 err
= fuse2fs_read_inode(fs
, child
, &inode
);
1448 ret
= translate_error(fs
, child
, err
);
1452 fuse2fs_set_uid(&inode
, ctxt
->uid
);
1453 fuse2fs_set_gid(&inode
, gid
);
1454 inode
.i_mode
= LINUX_S_IFDIR
| (mode
& ~S_ISUID
);
1456 inode
.i_mode
|= S_ISGID
;
1457 inode
.i_generation
= ff
->next_generation
++;
1460 err
= fuse2fs_write_inode(fs
, child
, &inode
);
1462 ret
= translate_error(fs
, child
, err
);
1466 /* Rewrite the directory block checksum, having set i_generation */
1467 if ((inode
.i_flags
& EXT4_INLINE_DATA_FL
) ||
1468 !ext2fs_has_feature_metadata_csum(fs
->super
))
1470 err
= ext2fs_new_dir_block(fs
, child
, parent
, &block
);
1472 ret
= translate_error(fs
, child
, err
);
1475 err
= ext2fs_bmap2(fs
, child
, EXT2_INODE(&inode
), NULL
, 0, 0,
1478 ret
= translate_error(fs
, child
, err
);
1481 err
= ext2fs_write_dir_block4(fs
, blk
, block
, 0, child
);
1483 ret
= translate_error(fs
, child
, err
);
1487 ret
= propagate_default_acls(ff
, parent
, child
);
1492 ext2fs_free_mem(&block
);
1494 pthread_mutex_unlock(&ff
->bfl
);
1500 static int unlink_file_by_name(struct fuse2fs
*ff
, const char *path
)
1502 ext2_filsys fs
= ff
->fs
;
1505 char *filename
= strdup(path
);
1509 base_name
= strrchr(filename
, '/');
1511 *base_name
++ = '\0';
1512 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, filename
,
1516 return translate_error(fs
, 0, err
);
1519 dir
= EXT2_ROOT_INO
;
1520 base_name
= filename
;
1523 ret
= check_inum_access(ff
, dir
, W_OK
);
1529 dbg_printf(ff
, "%s: unlinking name=%s from dir=%d\n", __func__
,
1531 err
= ext2fs_unlink(fs
, dir
, base_name
, 0, 0);
1534 return translate_error(fs
, dir
, err
);
1536 return update_mtime(fs
, dir
, NULL
);
1539 static errcode_t
remove_ea_inodes(struct fuse2fs
*ff
, ext2_ino_t ino
,
1540 struct ext2_inode_large
*inode
)
1542 ext2_filsys fs
= ff
->fs
;
1543 struct ext2_xattr_handle
*h
;
1547 * The xattr handle maintains its own private copy of the inode, so
1548 * write ours to disk so that we can read it.
1550 err
= fuse2fs_write_inode(fs
, ino
, inode
);
1554 err
= ext2fs_xattrs_open(fs
, ino
, &h
);
1558 err
= ext2fs_xattrs_read(h
);
1562 err
= ext2fs_xattr_remove_all(h
);
1567 ext2fs_xattrs_close(&h
);
1569 /* Now read the inode back in. */
1570 return fuse2fs_read_inode(fs
, ino
, inode
);
1573 static int remove_inode(struct fuse2fs
*ff
, ext2_ino_t ino
)
1575 ext2_filsys fs
= ff
->fs
;
1577 struct ext2_inode_large inode
;
1580 err
= fuse2fs_read_inode(fs
, ino
, &inode
);
1582 ret
= translate_error(fs
, ino
, err
);
1585 dbg_printf(ff
, "%s: put ino=%d links=%d\n", __func__
, ino
,
1586 inode
.i_links_count
);
1588 switch (inode
.i_links_count
) {
1590 return 0; /* XXX: already done? */
1592 inode
.i_links_count
--;
1593 ext2fs_set_dtime(fs
, EXT2_INODE(&inode
));
1596 inode
.i_links_count
--;
1599 ret
= update_ctime(fs
, ino
, &inode
);
1603 if (inode
.i_links_count
)
1606 if (ext2fs_has_feature_ea_inode(fs
->super
)) {
1607 err
= remove_ea_inodes(ff
, ino
, &inode
);
1612 /* Nobody holds this file; free its blocks! */
1613 err
= ext2fs_free_ext_attr(fs
, ino
, &inode
);
1617 if (ext2fs_inode_has_valid_blocks2(fs
, EXT2_INODE(&inode
))) {
1618 err
= ext2fs_punch(fs
, ino
, EXT2_INODE(&inode
), NULL
,
1621 ret
= translate_error(fs
, ino
, err
);
1626 ext2fs_inode_alloc_stats2(fs
, ino
, -1,
1627 LINUX_S_ISDIR(inode
.i_mode
));
1630 err
= fuse2fs_write_inode(fs
, ino
, &inode
);
1632 ret
= translate_error(fs
, ino
, err
);
1639 static int __op_unlink(struct fuse2fs
*ff
, const char *path
)
1641 ext2_filsys fs
= ff
->fs
;
1646 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
1648 ret
= translate_error(fs
, 0, err
);
1652 ret
= check_inum_access(ff
, ino
, W_OK
);
1656 ret
= unlink_file_by_name(ff
, path
);
1660 ret
= remove_inode(ff
, ino
);
1667 static int op_unlink(const char *path
)
1669 struct fuse_context
*ctxt
= fuse_get_context();
1670 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
1673 FUSE2FS_CHECK_CONTEXT(ff
);
1674 pthread_mutex_lock(&ff
->bfl
);
1675 ret
= __op_unlink(ff
, path
);
1676 pthread_mutex_unlock(&ff
->bfl
);
1685 static int rmdir_proc(ext2_ino_t dir
EXT2FS_ATTR((unused
)),
1686 int entry
EXT2FS_ATTR((unused
)),
1687 struct ext2_dir_entry
*dirent
,
1688 int offset
EXT2FS_ATTR((unused
)),
1689 int blocksize
EXT2FS_ATTR((unused
)),
1690 char *buf
EXT2FS_ATTR((unused
)),
1693 struct rd_struct
*rds
= (struct rd_struct
*) private;
1695 if (dirent
->inode
== 0)
1697 if (((dirent
->name_len
& 0xFF) == 1) && (dirent
->name
[0] == '.'))
1699 if (((dirent
->name_len
& 0xFF) == 2) && (dirent
->name
[0] == '.') &&
1700 (dirent
->name
[1] == '.')) {
1701 rds
->parent
= dirent
->inode
;
1708 static int __op_rmdir(struct fuse2fs
*ff
, const char *path
)
1710 ext2_filsys fs
= ff
->fs
;
1713 struct ext2_inode_large inode
;
1714 struct rd_struct rds
;
1717 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &child
);
1719 ret
= translate_error(fs
, 0, err
);
1722 dbg_printf(ff
, "%s: rmdir path=%s ino=%d\n", __func__
, path
, child
);
1724 ret
= check_inum_access(ff
, child
, W_OK
);
1731 err
= ext2fs_dir_iterate2(fs
, child
, 0, 0, rmdir_proc
, &rds
);
1733 ret
= translate_error(fs
, child
, err
);
1737 /* the kernel checks parent permissions before emptiness */
1738 if (rds
.parent
== 0) {
1739 ret
= translate_error(fs
, child
, EXT2_ET_FILESYSTEM_CORRUPTED
);
1743 ret
= check_inum_access(ff
, rds
.parent
, W_OK
);
1747 if (rds
.empty
== 0) {
1752 ret
= unlink_file_by_name(ff
, path
);
1755 /* Directories have to be "removed" twice. */
1756 ret
= remove_inode(ff
, child
);
1759 ret
= remove_inode(ff
, child
);
1764 dbg_printf(ff
, "%s: decr dir=%d link count\n", __func__
,
1766 err
= fuse2fs_read_inode(fs
, rds
.parent
, &inode
);
1768 ret
= translate_error(fs
, rds
.parent
, err
);
1771 if (inode
.i_links_count
> 1)
1772 inode
.i_links_count
--;
1773 ret
= update_mtime(fs
, rds
.parent
, &inode
);
1776 err
= fuse2fs_write_inode(fs
, rds
.parent
, &inode
);
1778 ret
= translate_error(fs
, rds
.parent
, err
);
1787 static int op_rmdir(const char *path
)
1789 struct fuse_context
*ctxt
= fuse_get_context();
1790 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
1793 FUSE2FS_CHECK_CONTEXT(ff
);
1794 pthread_mutex_lock(&ff
->bfl
);
1795 ret
= __op_rmdir(ff
, path
);
1796 pthread_mutex_unlock(&ff
->bfl
);
1800 static int op_symlink(const char *src
, const char *dest
)
1802 struct fuse_context
*ctxt
= fuse_get_context();
1803 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
1805 ext2_ino_t parent
, child
;
1809 struct ext2_inode_large inode
;
1813 FUSE2FS_CHECK_CONTEXT(ff
);
1815 dbg_printf(ff
, "%s: symlink %s to %s\n", __func__
, src
, dest
);
1816 temp_path
= strdup(dest
);
1821 node_name
= strrchr(temp_path
, '/');
1830 pthread_mutex_lock(&ff
->bfl
);
1831 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, temp_path
,
1835 ret
= translate_error(fs
, 0, err
);
1839 ret
= check_inum_access(ff
, parent
, A_OK
| W_OK
);
1843 err
= fuse2fs_new_child_gid(ff
, parent
, &gid
, NULL
);
1847 /* Create symlink */
1848 err
= ext2fs_symlink(fs
, parent
, 0, node_name
, src
);
1849 if (err
== EXT2_ET_DIR_NO_SPACE
) {
1850 err
= ext2fs_expand_dir(fs
, parent
);
1852 ret
= translate_error(fs
, parent
, err
);
1856 err
= ext2fs_symlink(fs
, parent
, 0, node_name
, src
);
1859 ret
= translate_error(fs
, parent
, err
);
1863 /* Update parent dir's mtime */
1864 ret
= update_mtime(fs
, parent
, NULL
);
1868 /* Still have to update the uid/gid of the symlink */
1869 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, temp_path
,
1872 ret
= translate_error(fs
, 0, err
);
1875 dbg_printf(ff
, "%s: symlinking ino=%d/name=%s to dir=%d\n", __func__
,
1876 child
, node_name
, parent
);
1878 err
= fuse2fs_read_inode(fs
, child
, &inode
);
1880 ret
= translate_error(fs
, child
, err
);
1884 fuse2fs_set_uid(&inode
, ctxt
->uid
);
1885 fuse2fs_set_gid(&inode
, gid
);
1886 inode
.i_generation
= ff
->next_generation
++;
1889 err
= fuse2fs_write_inode(fs
, child
, &inode
);
1891 ret
= translate_error(fs
, child
, err
);
1895 pthread_mutex_unlock(&ff
->bfl
);
1901 struct update_dotdot
{
1902 ext2_ino_t new_dotdot
;
1905 static int update_dotdot_helper(ext2_ino_t dir
EXT2FS_ATTR((unused
)),
1906 int entry
EXT2FS_ATTR((unused
)),
1907 struct ext2_dir_entry
*dirent
,
1908 int offset
EXT2FS_ATTR((unused
)),
1909 int blocksize
EXT2FS_ATTR((unused
)),
1910 char *buf
EXT2FS_ATTR((unused
)),
1913 struct update_dotdot
*ud
= priv_data
;
1915 if (ext2fs_dirent_name_len(dirent
) == 2 &&
1916 dirent
->name
[0] == '.' && dirent
->name
[1] == '.') {
1917 dirent
->inode
= ud
->new_dotdot
;
1918 return DIRENT_CHANGED
| DIRENT_ABORT
;
1924 static int op_rename(const char *from
, const char *to
1925 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
1926 , unsigned int flags
EXT2FS_ATTR((unused
))
1930 struct fuse_context
*ctxt
= fuse_get_context();
1931 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
1934 ext2_ino_t from_ino
, to_ino
, to_dir_ino
, from_dir_ino
;
1935 char *temp_to
= NULL
, *temp_from
= NULL
;
1937 struct ext2_inode inode
;
1938 struct update_dotdot ud
;
1941 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
1942 /* renameat2 is not supported */
1947 FUSE2FS_CHECK_CONTEXT(ff
);
1949 dbg_printf(ff
, "%s: renaming %s to %s\n", __func__
, from
, to
);
1950 pthread_mutex_lock(&ff
->bfl
);
1951 if (!fs_can_allocate(ff
, 5)) {
1956 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, from
, &from_ino
);
1957 if (err
|| from_ino
== 0) {
1958 ret
= translate_error(fs
, 0, err
);
1962 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, to
, &to_ino
);
1963 if (err
&& err
!= EXT2_ET_FILE_NOT_FOUND
) {
1964 ret
= translate_error(fs
, 0, err
);
1968 if (err
== EXT2_ET_FILE_NOT_FOUND
)
1971 /* Already the same file? */
1972 if (to_ino
!= 0 && to_ino
== from_ino
) {
1977 ret
= check_inum_access(ff
, from_ino
, W_OK
);
1982 ret
= check_inum_access(ff
, to_ino
, W_OK
);
1987 temp_to
= strdup(to
);
1993 temp_from
= strdup(from
);
1999 /* Find parent dir of the source and check write access */
2000 cp
= strrchr(temp_from
, '/');
2008 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, temp_from
,
2012 ret
= translate_error(fs
, 0, err
);
2015 if (from_dir_ino
== 0) {
2020 ret
= check_inum_access(ff
, from_dir_ino
, W_OK
);
2024 /* Find parent dir of the destination and check write access */
2025 cp
= strrchr(temp_to
, '/');
2033 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, temp_to
,
2037 ret
= translate_error(fs
, 0, err
);
2040 if (to_dir_ino
== 0) {
2045 ret
= check_inum_access(ff
, to_dir_ino
, W_OK
);
2049 /* If the target exists, unlink it first */
2051 err
= ext2fs_read_inode(fs
, to_ino
, &inode
);
2053 ret
= translate_error(fs
, to_ino
, err
);
2057 dbg_printf(ff
, "%s: unlinking %s ino=%d\n", __func__
,
2058 LINUX_S_ISDIR(inode
.i_mode
) ? "dir" : "file",
2060 if (LINUX_S_ISDIR(inode
.i_mode
))
2061 ret
= __op_rmdir(ff
, to
);
2063 ret
= __op_unlink(ff
, to
);
2068 /* Get ready to do the move */
2069 err
= ext2fs_read_inode(fs
, from_ino
, &inode
);
2071 ret
= translate_error(fs
, from_ino
, err
);
2075 /* Link in the new file */
2076 dbg_printf(ff
, "%s: linking ino=%d/path=%s to dir=%d\n", __func__
,
2077 from_ino
, cp
+ 1, to_dir_ino
);
2078 err
= ext2fs_link(fs
, to_dir_ino
, cp
+ 1, from_ino
,
2079 ext2_file_type(inode
.i_mode
) | EXT2FS_LINK_EXPAND
);
2081 ret
= translate_error(fs
, to_dir_ino
, err
);
2085 /* Update '..' pointer if dir */
2086 err
= ext2fs_read_inode(fs
, from_ino
, &inode
);
2088 ret
= translate_error(fs
, from_ino
, err
);
2092 if (LINUX_S_ISDIR(inode
.i_mode
)) {
2093 ud
.new_dotdot
= to_dir_ino
;
2094 dbg_printf(ff
, "%s: updating .. entry for dir=%d\n", __func__
,
2096 err
= ext2fs_dir_iterate2(fs
, from_ino
, 0, NULL
,
2097 update_dotdot_helper
, &ud
);
2099 ret
= translate_error(fs
, from_ino
, err
);
2103 /* Decrease from_dir_ino's links_count */
2104 dbg_printf(ff
, "%s: moving linkcount from dir=%d to dir=%d\n",
2105 __func__
, from_dir_ino
, to_dir_ino
);
2106 err
= ext2fs_read_inode(fs
, from_dir_ino
, &inode
);
2108 ret
= translate_error(fs
, from_dir_ino
, err
);
2111 inode
.i_links_count
--;
2112 err
= ext2fs_write_inode(fs
, from_dir_ino
, &inode
);
2114 ret
= translate_error(fs
, from_dir_ino
, err
);
2118 /* Increase to_dir_ino's links_count */
2119 err
= ext2fs_read_inode(fs
, to_dir_ino
, &inode
);
2121 ret
= translate_error(fs
, to_dir_ino
, err
);
2124 inode
.i_links_count
++;
2125 err
= ext2fs_write_inode(fs
, to_dir_ino
, &inode
);
2127 ret
= translate_error(fs
, to_dir_ino
, err
);
2132 /* Update timestamps */
2133 ret
= update_ctime(fs
, from_ino
, NULL
);
2137 ret
= update_mtime(fs
, to_dir_ino
, NULL
);
2141 /* Remove the old file */
2142 ret
= unlink_file_by_name(ff
, from
);
2146 /* Flush the whole mess out */
2147 err
= ext2fs_flush2(fs
, 0);
2149 ret
= translate_error(fs
, 0, err
);
2155 pthread_mutex_unlock(&ff
->bfl
);
2159 static int op_link(const char *src
, const char *dest
)
2161 struct fuse_context
*ctxt
= fuse_get_context();
2162 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2167 ext2_ino_t parent
, ino
;
2168 struct ext2_inode_large inode
;
2171 FUSE2FS_CHECK_CONTEXT(ff
);
2173 dbg_printf(ff
, "%s: src=%s dest=%s\n", __func__
, src
, dest
);
2174 temp_path
= strdup(dest
);
2179 node_name
= strrchr(temp_path
, '/');
2188 pthread_mutex_lock(&ff
->bfl
);
2189 if (!fs_can_allocate(ff
, 2)) {
2194 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, temp_path
,
2202 ret
= check_inum_access(ff
, parent
, A_OK
| W_OK
);
2206 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, src
, &ino
);
2207 if (err
|| ino
== 0) {
2208 ret
= translate_error(fs
, 0, err
);
2212 err
= fuse2fs_read_inode(fs
, ino
, &inode
);
2214 ret
= translate_error(fs
, ino
, err
);
2218 ret
= check_iflags_access(ff
, ino
, EXT2_INODE(&inode
), W_OK
);
2222 inode
.i_links_count
++;
2223 ret
= update_ctime(fs
, ino
, &inode
);
2227 err
= fuse2fs_write_inode(fs
, ino
, &inode
);
2229 ret
= translate_error(fs
, ino
, err
);
2233 dbg_printf(ff
, "%s: linking ino=%d/name=%s to dir=%d\n", __func__
, ino
,
2235 err
= ext2fs_link(fs
, parent
, node_name
, ino
,
2236 ext2_file_type(inode
.i_mode
) | EXT2FS_LINK_EXPAND
);
2238 ret
= translate_error(fs
, parent
, err
);
2242 ret
= update_mtime(fs
, parent
, NULL
);
2247 pthread_mutex_unlock(&ff
->bfl
);
2253 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
2254 /* Obtain group ids of the process that sent us a command(?) */
2255 static int get_req_groups(struct fuse2fs
*ff
, gid_t
**gids
, size_t *nr_gids
)
2257 ext2_filsys fs
= ff
->fs
;
2260 int nr
= 32; /* nobody has more than 32 groups right? */
2264 err
= ext2fs_get_array(nr
, sizeof(gid_t
), &array
);
2266 return translate_error(fs
, 0, err
);
2268 ret
= fuse_getgroups(nr
, array
);
2278 ext2fs_free_mem(&array
);
2287 * Is this file's group id in the set of groups associated with the process
2288 * that initiated the fuse request? Returns 1 for yes, 0 for no, or a negative
2291 static int in_file_group(struct fuse_context
*ctxt
,
2292 const struct ext2_inode_large
*inode
)
2294 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2296 size_t i
, nr_gids
= 0;
2297 gid_t gid
= inode_gid(*inode
);
2300 ret
= get_req_groups(ff
, &gids
, &nr_gids
);
2304 for (i
= 0; i
< nr_gids
; i
++)
2310 static int in_file_group(struct fuse_context
*ctxt
,
2311 const struct ext2_inode_large
*inode
)
2313 return ctxt
->gid
== inode_gid(*inode
);
2317 static int op_chmod(const char *path
, mode_t mode
2318 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
2319 , struct fuse_file_info
*fi
EXT2FS_ATTR((unused
))
2323 struct fuse_context
*ctxt
= fuse_get_context();
2324 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2328 struct ext2_inode_large inode
;
2331 FUSE2FS_CHECK_CONTEXT(ff
);
2333 pthread_mutex_lock(&ff
->bfl
);
2334 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
2336 ret
= translate_error(fs
, 0, err
);
2339 dbg_printf(ff
, "%s: path=%s mode=0%o ino=%d\n", __func__
, path
, mode
, ino
);
2341 err
= fuse2fs_read_inode(fs
, ino
, &inode
);
2343 ret
= translate_error(fs
, ino
, err
);
2347 ret
= check_iflags_access(ff
, ino
, EXT2_INODE(&inode
), W_OK
);
2351 if (want_check_owner(ff
, ctxt
) && ctxt
->uid
!= inode_uid(inode
)) {
2357 * XXX: We should really check that the inode gid is not in /any/
2358 * of the user's groups, but FUSE only tells us about the primary
2361 if (!is_superuser(ff
, ctxt
)) {
2362 ret
= in_file_group(ctxt
, &inode
);
2370 inode
.i_mode
&= ~0xFFF;
2371 inode
.i_mode
|= mode
& 0xFFF;
2373 dbg_printf(ff
, "%s: path=%s new_mode=0%o ino=%d\n", __func__
,
2374 path
, inode
.i_mode
, ino
);
2376 ret
= update_ctime(fs
, ino
, &inode
);
2380 err
= fuse2fs_write_inode(fs
, ino
, &inode
);
2382 ret
= translate_error(fs
, ino
, err
);
2387 pthread_mutex_unlock(&ff
->bfl
);
2391 static int op_chown(const char *path
, uid_t owner
, gid_t group
2392 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
2393 , struct fuse_file_info
*fi
EXT2FS_ATTR((unused
))
2397 struct fuse_context
*ctxt
= fuse_get_context();
2398 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2402 struct ext2_inode_large inode
;
2405 FUSE2FS_CHECK_CONTEXT(ff
);
2407 pthread_mutex_lock(&ff
->bfl
);
2408 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
2410 ret
= translate_error(fs
, 0, err
);
2413 dbg_printf(ff
, "%s: path=%s owner=%d group=%d ino=%d\n", __func__
,
2414 path
, owner
, group
, ino
);
2416 err
= fuse2fs_read_inode(fs
, ino
, &inode
);
2418 ret
= translate_error(fs
, ino
, err
);
2422 ret
= check_iflags_access(ff
, ino
, EXT2_INODE(&inode
), W_OK
);
2426 /* FUSE seems to feed us ~0 to mean "don't change" */
2427 if (owner
!= (uid_t
) ~0) {
2428 /* Only root gets to change UID. */
2429 if (want_check_owner(ff
, ctxt
) &&
2430 !(inode_uid(inode
) == ctxt
->uid
&& owner
== ctxt
->uid
)) {
2434 fuse2fs_set_uid(&inode
, owner
);
2437 if (group
!= (gid_t
) ~0) {
2438 /* Only root or the owner get to change GID. */
2439 if (want_check_owner(ff
, ctxt
) &&
2440 inode_uid(inode
) != ctxt
->uid
) {
2445 /* XXX: We /should/ check group membership but FUSE */
2446 fuse2fs_set_gid(&inode
, group
);
2449 ret
= update_ctime(fs
, ino
, &inode
);
2453 err
= fuse2fs_write_inode(fs
, ino
, &inode
);
2455 ret
= translate_error(fs
, ino
, err
);
2460 pthread_mutex_unlock(&ff
->bfl
);
2464 static int fuse2fs_punch_posteof(struct fuse2fs
*ff
, ext2_ino_t ino
,
2467 ext2_filsys fs
= ff
->fs
;
2468 struct ext2_inode_large inode
;
2469 blk64_t truncate_block
= FUSE2FS_B_TO_FSB(ff
, new_size
);
2472 err
= fuse2fs_read_inode(fs
, ino
, &inode
);
2474 return translate_error(fs
, ino
, err
);
2476 err
= ext2fs_punch(fs
, ino
, EXT2_INODE(&inode
), 0, truncate_block
,
2479 return translate_error(fs
, ino
, err
);
2481 err
= fuse2fs_write_inode(fs
, ino
, &inode
);
2483 return translate_error(fs
, ino
, err
);
2488 static int fuse2fs_truncate(struct fuse2fs
*ff
, ext2_ino_t ino
, off_t new_size
)
2490 ext2_filsys fs
= ff
->fs
;
2496 err
= ext2fs_file_open(fs
, ino
, EXT2_FILE_WRITE
, &file
);
2498 return translate_error(fs
, ino
, err
);
2500 err
= ext2fs_file_get_lsize(file
, &old_isize
);
2502 ret
= translate_error(fs
, ino
, err
);
2506 dbg_printf(ff
, "%s: ino=%u isize=0x%llx new_size=0x%llx\n", __func__
,
2508 (unsigned long long)old_isize
,
2509 (unsigned long long)new_size
);
2511 err
= ext2fs_file_set_size2(file
, new_size
);
2513 ret
= translate_error(fs
, ino
, err
);
2516 err
= ext2fs_file_close(file
);
2520 return translate_error(fs
, ino
, err
);
2522 ret
= update_mtime(fs
, ino
, NULL
);
2527 * Truncating to the current size is usually understood to mean that
2528 * we should clear out post-EOF preallocations.
2530 if (new_size
== old_isize
)
2531 return fuse2fs_punch_posteof(ff
, ino
, new_size
);
2536 static int op_truncate(const char *path
, off_t len
2537 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
2538 , struct fuse_file_info
*fi
EXT2FS_ATTR((unused
))
2542 struct fuse_context
*ctxt
= fuse_get_context();
2543 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2549 FUSE2FS_CHECK_CONTEXT(ff
);
2551 pthread_mutex_lock(&ff
->bfl
);
2552 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
2554 ret
= translate_error(fs
, 0, err
);
2561 dbg_printf(ff
, "%s: ino=%d len=%jd\n", __func__
, ino
, (intmax_t) len
);
2563 ret
= check_inum_access(ff
, ino
, W_OK
);
2567 ret
= fuse2fs_truncate(ff
, ino
, len
);
2572 pthread_mutex_unlock(&ff
->bfl
);
2577 static void detect_linux_executable_open(int kernel_flags
, int *access_check
,
2578 int *e2fs_open_flags
)
2581 * On Linux, execve will bleed __FMODE_EXEC into the file mode flags,
2582 * and FUSE is more than happy to let that slip through.
2584 if (kernel_flags
& 0x20) {
2585 *access_check
= X_OK
;
2586 *e2fs_open_flags
&= ~EXT2_FILE_WRITE
;
2590 static void detect_linux_executable_open(int kernel_flags
, int *access_check
,
2591 int *e2fs_open_flags
)
2595 #endif /* __linux__ */
2597 static int __op_open(struct fuse2fs
*ff
, const char *path
,
2598 struct fuse_file_info
*fp
)
2600 ext2_filsys fs
= ff
->fs
;
2602 struct fuse2fs_file_handle
*file
;
2603 int check
= 0, ret
= 0;
2605 dbg_printf(ff
, "%s: path=%s oflags=0o%o\n", __func__
, path
, fp
->flags
);
2606 err
= ext2fs_get_mem(sizeof(*file
), &file
);
2608 return translate_error(fs
, 0, err
);
2609 file
->magic
= FUSE2FS_FILE_MAGIC
;
2611 file
->open_flags
= 0;
2612 switch (fp
->flags
& O_ACCMODE
) {
2618 file
->open_flags
|= EXT2_FILE_WRITE
;
2621 check
= R_OK
| W_OK
;
2622 file
->open_flags
|= EXT2_FILE_WRITE
;
2625 if (fp
->flags
& O_APPEND
) {
2626 /* the kernel doesn't allow truncation of an append-only file */
2627 if (fp
->flags
& O_TRUNC
) {
2635 detect_linux_executable_open(fp
->flags
, &check
, &file
->open_flags
);
2637 if (fp
->flags
& O_CREAT
)
2638 file
->open_flags
|= EXT2_FILE_CREATE
;
2640 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &file
->ino
);
2641 if (err
|| file
->ino
== 0) {
2642 ret
= translate_error(fs
, 0, err
);
2645 dbg_printf(ff
, "%s: ino=%d\n", __func__
, file
->ino
);
2647 ret
= check_inum_access(ff
, file
->ino
, check
);
2650 * In a regular (Linux) fs driver, the kernel will open
2651 * binaries for reading if the user has --x privileges (i.e.
2652 * execute without read). Since the kernel doesn't have any
2653 * way to tell us if it's opening a file via execve, we'll
2654 * just assume that allowing access is ok if asking for ro mode
2655 * fails but asking for x mode succeeds. Of course we can
2656 * also employ undocumented hacks (see above).
2658 if (check
== R_OK
) {
2659 ret
= check_inum_access(ff
, file
->ino
, X_OK
);
2666 if (fp
->flags
& O_TRUNC
) {
2667 ret
= fuse2fs_truncate(ff
, file
->ino
, 0);
2672 fp
->fh
= (uintptr_t)file
;
2676 ext2fs_free_mem(&file
);
2680 static int op_open(const char *path
, struct fuse_file_info
*fp
)
2682 struct fuse_context
*ctxt
= fuse_get_context();
2683 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2686 FUSE2FS_CHECK_CONTEXT(ff
);
2687 pthread_mutex_lock(&ff
->bfl
);
2688 ret
= __op_open(ff
, path
, fp
);
2689 pthread_mutex_unlock(&ff
->bfl
);
2693 static int op_read(const char *path
EXT2FS_ATTR((unused
)), char *buf
,
2694 size_t len
, off_t offset
,
2695 struct fuse_file_info
*fp
)
2697 struct fuse_context
*ctxt
= fuse_get_context();
2698 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2699 struct fuse2fs_file_handle
*fh
=
2700 (struct fuse2fs_file_handle
*)(uintptr_t)fp
->fh
;
2704 unsigned int got
= 0;
2707 FUSE2FS_CHECK_CONTEXT(ff
);
2709 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
2710 dbg_printf(ff
, "%s: ino=%d off=%jd len=%jd\n", __func__
, fh
->ino
,
2711 (intmax_t) offset
, len
);
2712 pthread_mutex_lock(&ff
->bfl
);
2713 err
= ext2fs_file_open(fs
, fh
->ino
, fh
->open_flags
, &efp
);
2715 ret
= translate_error(fs
, fh
->ino
, err
);
2719 err
= ext2fs_file_llseek(efp
, offset
, SEEK_SET
, NULL
);
2721 ret
= translate_error(fs
, fh
->ino
, err
);
2725 err
= ext2fs_file_read(efp
, buf
, len
, &got
);
2727 ret
= translate_error(fs
, fh
->ino
, err
);
2732 err
= ext2fs_file_close(efp
);
2736 ret
= translate_error(fs
, fh
->ino
, err
);
2740 if (fs_writeable(fs
)) {
2741 ret
= update_atime(fs
, fh
->ino
);
2746 pthread_mutex_unlock(&ff
->bfl
);
2747 return got
? (int) got
: ret
;
2750 static int op_write(const char *path
EXT2FS_ATTR((unused
)),
2751 const char *buf
, size_t len
, off_t offset
,
2752 struct fuse_file_info
*fp
)
2754 struct fuse_context
*ctxt
= fuse_get_context();
2755 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2756 struct fuse2fs_file_handle
*fh
=
2757 (struct fuse2fs_file_handle
*)(uintptr_t)fp
->fh
;
2761 unsigned int got
= 0;
2764 FUSE2FS_CHECK_CONTEXT(ff
);
2766 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
2767 dbg_printf(ff
, "%s: ino=%d off=%jd len=%jd\n", __func__
, fh
->ino
,
2768 (intmax_t) offset
, (intmax_t) len
);
2769 pthread_mutex_lock(&ff
->bfl
);
2770 if (!fs_writeable(fs
)) {
2775 if (!fs_can_allocate(ff
, FUSE2FS_B_TO_FSB(ff
, len
))) {
2780 err
= ext2fs_file_open(fs
, fh
->ino
, fh
->open_flags
, &efp
);
2782 ret
= translate_error(fs
, fh
->ino
, err
);
2786 err
= ext2fs_file_llseek(efp
, offset
, SEEK_SET
, NULL
);
2788 ret
= translate_error(fs
, fh
->ino
, err
);
2792 err
= ext2fs_file_write(efp
, buf
, len
, &got
);
2794 ret
= translate_error(fs
, fh
->ino
, err
);
2798 err
= ext2fs_file_flush(efp
);
2801 ret
= translate_error(fs
, fh
->ino
, err
);
2806 err
= ext2fs_file_close(efp
);
2810 ret
= translate_error(fs
, fh
->ino
, err
);
2814 ret
= update_mtime(fs
, fh
->ino
, NULL
);
2819 pthread_mutex_unlock(&ff
->bfl
);
2820 return got
? (int) got
: ret
;
2823 static int op_release(const char *path
EXT2FS_ATTR((unused
)),
2824 struct fuse_file_info
*fp
)
2826 struct fuse_context
*ctxt
= fuse_get_context();
2827 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2828 struct fuse2fs_file_handle
*fh
=
2829 (struct fuse2fs_file_handle
*)(uintptr_t)fp
->fh
;
2834 FUSE2FS_CHECK_CONTEXT(ff
);
2836 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
2837 dbg_printf(ff
, "%s: ino=%d\n", __func__
, fh
->ino
);
2838 pthread_mutex_lock(&ff
->bfl
);
2839 if (fs_writeable(fs
) && fh
->open_flags
& EXT2_FILE_WRITE
) {
2840 err
= ext2fs_flush2(fs
, EXT2_FLAG_FLUSH_NO_SYNC
);
2842 ret
= translate_error(fs
, fh
->ino
, err
);
2845 pthread_mutex_unlock(&ff
->bfl
);
2847 ext2fs_free_mem(&fh
);
2852 static int op_fsync(const char *path
EXT2FS_ATTR((unused
)),
2853 int datasync
EXT2FS_ATTR((unused
)),
2854 struct fuse_file_info
*fp
)
2856 struct fuse_context
*ctxt
= fuse_get_context();
2857 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2858 struct fuse2fs_file_handle
*fh
=
2859 (struct fuse2fs_file_handle
*)(uintptr_t)fp
->fh
;
2864 FUSE2FS_CHECK_CONTEXT(ff
);
2866 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
2867 dbg_printf(ff
, "%s: ino=%d\n", __func__
, fh
->ino
);
2868 /* For now, flush everything, even if it's slow */
2869 pthread_mutex_lock(&ff
->bfl
);
2870 if (fs_writeable(fs
) && fh
->open_flags
& EXT2_FILE_WRITE
) {
2871 err
= ext2fs_flush2(fs
, 0);
2873 ret
= translate_error(fs
, fh
->ino
, err
);
2875 pthread_mutex_unlock(&ff
->bfl
);
2880 static int op_statfs(const char *path
EXT2FS_ATTR((unused
)),
2881 struct statvfs
*buf
)
2883 struct fuse_context
*ctxt
= fuse_get_context();
2884 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2887 blk64_t overhead
, reserved
, free
;
2889 FUSE2FS_CHECK_CONTEXT(ff
);
2890 dbg_printf(ff
, "%s: path=%s\n", __func__
, path
);
2892 pthread_mutex_lock(&ff
->bfl
);
2893 buf
->f_bsize
= fs
->blocksize
;
2899 overhead
= fs
->desc_blocks
+
2900 (blk64_t
)fs
->group_desc_count
*
2901 (fs
->inode_blocks_per_group
+ 2);
2902 reserved
= ext2fs_r_blocks_count(fs
->super
);
2904 reserved
= ext2fs_blocks_count(fs
->super
) / 10;
2905 free
= ext2fs_free_blocks_count(fs
->super
);
2907 buf
->f_blocks
= ext2fs_blocks_count(fs
->super
) - overhead
;
2908 buf
->f_bfree
= free
;
2909 if (free
< reserved
)
2912 buf
->f_bavail
= free
- reserved
;
2913 buf
->f_files
= fs
->super
->s_inodes_count
;
2914 buf
->f_ffree
= fs
->super
->s_free_inodes_count
;
2915 buf
->f_favail
= fs
->super
->s_free_inodes_count
;
2916 f
= (uint64_t *)fs
->super
->s_uuid
;
2922 if (!(fs
->flags
& EXT2_FLAG_RW
))
2923 buf
->f_flag
|= ST_RDONLY
;
2924 buf
->f_namemax
= EXT2_NAME_LEN
;
2925 pthread_mutex_unlock(&ff
->bfl
);
2930 static const char *valid_xattr_prefixes
[] = {
2938 static int validate_xattr_name(const char *name
)
2942 for (i
= 0; i
< ARRAY_SIZE(valid_xattr_prefixes
); i
++) {
2943 if (!strncmp(name
, valid_xattr_prefixes
[i
],
2944 strlen(valid_xattr_prefixes
[i
])))
2951 static int op_getxattr(const char *path
, const char *key
, char *value
,
2954 struct fuse_context
*ctxt
= fuse_get_context();
2955 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2963 if (!validate_xattr_name(key
))
2966 FUSE2FS_CHECK_CONTEXT(ff
);
2968 pthread_mutex_lock(&ff
->bfl
);
2969 if (!ext2fs_has_feature_xattr(fs
->super
)) {
2974 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
2975 if (err
|| ino
== 0) {
2976 ret
= translate_error(fs
, 0, err
);
2979 dbg_printf(ff
, "%s: ino=%d name=%s\n", __func__
, ino
, key
);
2981 ret
= check_inum_access(ff
, ino
, R_OK
);
2985 ret
= __getxattr(ff
, ino
, key
, &ptr
, &plen
);
2991 } else if (len
< plen
) {
2994 memcpy(value
, ptr
, plen
);
2998 ext2fs_free_mem(&ptr
);
3000 pthread_mutex_unlock(&ff
->bfl
);
3005 static int count_buffer_space(char *name
, char *value
EXT2FS_ATTR((unused
)),
3006 size_t value_len
EXT2FS_ATTR((unused
)),
3009 unsigned int *x
= data
;
3011 *x
= *x
+ strlen(name
) + 1;
3015 static int copy_names(char *name
, char *value
EXT2FS_ATTR((unused
)),
3016 size_t value_len
EXT2FS_ATTR((unused
)), void *data
)
3019 size_t name_len
= strlen(name
);
3021 memcpy(*b
, name
, name_len
+ 1);
3022 *b
= *b
+ name_len
+ 1;
3027 static int op_listxattr(const char *path
, char *names
, size_t len
)
3029 struct fuse_context
*ctxt
= fuse_get_context();
3030 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
3032 struct ext2_xattr_handle
*h
;
3038 FUSE2FS_CHECK_CONTEXT(ff
);
3040 pthread_mutex_lock(&ff
->bfl
);
3041 if (!ext2fs_has_feature_xattr(fs
->super
)) {
3046 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
3047 if (err
|| ino
== 0) {
3048 ret
= translate_error(fs
, ino
, err
);
3051 dbg_printf(ff
, "%s: ino=%d\n", __func__
, ino
);
3053 ret
= check_inum_access(ff
, ino
, R_OK
);
3057 err
= ext2fs_xattrs_open(fs
, ino
, &h
);
3059 ret
= translate_error(fs
, ino
, err
);
3063 err
= ext2fs_xattrs_read(h
);
3065 ret
= translate_error(fs
, ino
, err
);
3069 /* Count buffer space needed for names */
3071 err
= ext2fs_xattrs_iterate(h
, count_buffer_space
, &bufsz
);
3073 ret
= translate_error(fs
, ino
, err
);
3080 } else if (len
< bufsz
) {
3085 /* Copy names out */
3086 memset(names
, 0, len
);
3087 err
= ext2fs_xattrs_iterate(h
, copy_names
, &names
);
3089 ret
= translate_error(fs
, ino
, err
);
3094 err
= ext2fs_xattrs_close(&h
);
3096 ret
= translate_error(fs
, ino
, err
);
3098 pthread_mutex_unlock(&ff
->bfl
);
3103 static int op_setxattr(const char *path
EXT2FS_ATTR((unused
)),
3104 const char *key
, const char *value
,
3105 size_t len
, int flags
)
3107 struct fuse_context
*ctxt
= fuse_get_context();
3108 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
3110 struct ext2_xattr_handle
*h
;
3115 if (flags
& ~(XATTR_CREATE
| XATTR_REPLACE
))
3118 if (!validate_xattr_name(key
))
3121 FUSE2FS_CHECK_CONTEXT(ff
);
3123 pthread_mutex_lock(&ff
->bfl
);
3124 if (!ext2fs_has_feature_xattr(fs
->super
)) {
3129 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
3130 if (err
|| ino
== 0) {
3131 ret
= translate_error(fs
, 0, err
);
3134 dbg_printf(ff
, "%s: ino=%d name=%s\n", __func__
, ino
, key
);
3136 ret
= check_inum_access(ff
, ino
, W_OK
);
3137 if (ret
== -EACCES
) {
3143 err
= ext2fs_xattrs_open(fs
, ino
, &h
);
3145 ret
= translate_error(fs
, ino
, err
);
3149 err
= ext2fs_xattrs_read(h
);
3151 ret
= translate_error(fs
, ino
, err
);
3155 if (flags
& (XATTR_CREATE
| XATTR_REPLACE
)) {
3159 err
= ext2fs_xattr_get(h
, key
, &buf
, &buflen
);
3161 case EXT2_ET_EA_KEY_NOT_FOUND
:
3162 if (flags
& XATTR_REPLACE
) {
3168 ext2fs_free_mem(&buf
);
3169 if (flags
& XATTR_CREATE
) {
3175 ret
= translate_error(fs
, ino
, err
);
3180 err
= ext2fs_xattr_set(h
, key
, value
, len
);
3182 ret
= translate_error(fs
, ino
, err
);
3186 ret
= update_ctime(fs
, ino
, NULL
);
3188 err
= ext2fs_xattrs_close(&h
);
3190 ret
= translate_error(fs
, ino
, err
);
3192 pthread_mutex_unlock(&ff
->bfl
);
3197 static int op_removexattr(const char *path
, const char *key
)
3199 struct fuse_context
*ctxt
= fuse_get_context();
3200 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
3202 struct ext2_xattr_handle
*h
;
3210 * Once in a while libfuse gives us a no-name xattr to delete as part
3211 * of clearing ACLs. Just pretend we cleared them.
3216 if (!validate_xattr_name(key
))
3219 FUSE2FS_CHECK_CONTEXT(ff
);
3221 pthread_mutex_lock(&ff
->bfl
);
3222 if (!ext2fs_has_feature_xattr(fs
->super
)) {
3227 if (!fs_can_allocate(ff
, 1)) {
3232 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
3233 if (err
|| ino
== 0) {
3234 ret
= translate_error(fs
, 0, err
);
3237 dbg_printf(ff
, "%s: ino=%d name=%s\n", __func__
, ino
, key
);
3239 ret
= check_inum_access(ff
, ino
, W_OK
);
3243 err
= ext2fs_xattrs_open(fs
, ino
, &h
);
3245 ret
= translate_error(fs
, ino
, err
);
3249 err
= ext2fs_xattrs_read(h
);
3251 ret
= translate_error(fs
, ino
, err
);
3255 err
= ext2fs_xattr_get(h
, key
, &buf
, &buflen
);
3257 case EXT2_ET_EA_KEY_NOT_FOUND
:
3259 * ACLs are special snowflakes that require a 0 return when
3260 * the ACL never existed in the first place.
3262 if (!strncmp(XATTR_SECURITY_PREFIX
, key
,
3263 XATTR_SECURITY_PREFIX_LEN
))
3269 ext2fs_free_mem(&buf
);
3272 ret
= translate_error(fs
, ino
, err
);
3276 err
= ext2fs_xattr_remove(h
, key
);
3278 ret
= translate_error(fs
, ino
, err
);
3282 ret
= update_ctime(fs
, ino
, NULL
);
3284 err
= ext2fs_xattrs_close(&h
);
3286 ret
= translate_error(fs
, ino
, err
);
3288 pthread_mutex_unlock(&ff
->bfl
);
3293 struct readdir_iter
{
3296 fuse_fill_dir_t func
;
3299 static inline mode_t
dirent_fmode(ext2_filsys fs
,
3300 const struct ext2_dir_entry
*dirent
)
3302 if (!ext2fs_has_feature_filetype(fs
->super
))
3305 switch (ext2fs_dirent_file_type(dirent
)) {
3306 case EXT2_FT_REG_FILE
:
3310 case EXT2_FT_CHRDEV
:
3312 case EXT2_FT_BLKDEV
:
3318 case EXT2_FT_SYMLINK
:
3325 static int op_readdir_iter(ext2_ino_t dir
EXT2FS_ATTR((unused
)),
3326 int entry
EXT2FS_ATTR((unused
)),
3327 struct ext2_dir_entry
*dirent
,
3328 int offset
EXT2FS_ATTR((unused
)),
3329 int blocksize
EXT2FS_ATTR((unused
)),
3330 char *buf
EXT2FS_ATTR((unused
)), void *data
)
3332 struct readdir_iter
*i
= data
;
3333 char namebuf
[EXT2_NAME_LEN
+ 1];
3334 struct stat stat
= {
3335 .st_ino
= dirent
->inode
,
3336 .st_mode
= dirent_fmode(i
->fs
, dirent
),
3340 memcpy(namebuf
, dirent
->name
, dirent
->name_len
& 0xFF);
3341 namebuf
[dirent
->name_len
& 0xFF] = 0;
3342 ret
= i
->func(i
->buf
, namebuf
, &stat
, 0
3343 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
3348 return DIRENT_ABORT
;
3353 static int op_readdir(const char *path
EXT2FS_ATTR((unused
)),
3354 void *buf
, fuse_fill_dir_t fill_func
,
3355 off_t offset
EXT2FS_ATTR((unused
)),
3356 struct fuse_file_info
*fp
3357 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
3358 , enum fuse_readdir_flags flags
EXT2FS_ATTR((unused
))
3362 struct fuse_context
*ctxt
= fuse_get_context();
3363 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
3364 struct fuse2fs_file_handle
*fh
=
3365 (struct fuse2fs_file_handle
*)(uintptr_t)fp
->fh
;
3367 struct readdir_iter i
;
3370 FUSE2FS_CHECK_CONTEXT(ff
);
3372 FUSE2FS_CHECK_MAGIC(i
.fs
, fh
, FUSE2FS_FILE_MAGIC
);
3373 dbg_printf(ff
, "%s: ino=%d\n", __func__
, fh
->ino
);
3374 pthread_mutex_lock(&ff
->bfl
);
3377 err
= ext2fs_dir_iterate2(i
.fs
, fh
->ino
, 0, NULL
, op_readdir_iter
, &i
);
3379 ret
= translate_error(i
.fs
, fh
->ino
, err
);
3383 if (fs_writeable(i
.fs
)) {
3384 ret
= update_atime(i
.fs
, fh
->ino
);
3389 pthread_mutex_unlock(&ff
->bfl
);
3393 static int op_access(const char *path
, int mask
)
3395 struct fuse_context
*ctxt
= fuse_get_context();
3396 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
3402 FUSE2FS_CHECK_CONTEXT(ff
);
3404 dbg_printf(ff
, "%s: path=%s mask=0x%x\n", __func__
, path
, mask
);
3405 pthread_mutex_lock(&ff
->bfl
);
3406 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
3407 if (err
|| ino
== 0) {
3408 ret
= translate_error(fs
, 0, err
);
3412 ret
= check_inum_access(ff
, ino
, mask
);
3417 pthread_mutex_unlock(&ff
->bfl
);
3421 static int op_create(const char *path
, mode_t mode
, struct fuse_file_info
*fp
)
3423 struct fuse_context
*ctxt
= fuse_get_context();
3424 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
3426 ext2_ino_t parent
, child
;
3431 struct ext2_inode_large inode
;
3435 FUSE2FS_CHECK_CONTEXT(ff
);
3437 dbg_printf(ff
, "%s: path=%s mode=0%o\n", __func__
, path
, mode
);
3438 temp_path
= strdup(path
);
3443 node_name
= strrchr(temp_path
, '/');
3452 pthread_mutex_lock(&ff
->bfl
);
3453 if (!fs_can_allocate(ff
, 1)) {
3458 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, temp_path
,
3461 ret
= translate_error(fs
, 0, err
);
3465 ret
= check_inum_access(ff
, parent
, A_OK
| W_OK
);
3469 err
= fuse2fs_new_child_gid(ff
, parent
, &gid
, NULL
);
3475 filetype
= ext2_file_type(mode
);
3477 err
= ext2fs_new_inode(fs
, parent
, mode
, 0, &child
);
3479 ret
= translate_error(fs
, parent
, err
);
3483 dbg_printf(ff
, "%s: creating ino=%d/name=%s in dir=%d\n", __func__
, child
,
3485 err
= ext2fs_link(fs
, parent
, node_name
, child
,
3486 filetype
| EXT2FS_LINK_EXPAND
);
3488 ret
= translate_error(fs
, parent
, err
);
3492 ret
= update_mtime(fs
, parent
, NULL
);
3496 memset(&inode
, 0, sizeof(inode
));
3497 inode
.i_mode
= mode
;
3498 inode
.i_links_count
= 1;
3499 inode
.i_extra_isize
= sizeof(struct ext2_inode_large
) -
3500 EXT2_GOOD_OLD_INODE_SIZE
;
3501 fuse2fs_set_uid(&inode
, ctxt
->uid
);
3502 fuse2fs_set_gid(&inode
, gid
);
3503 if (ext2fs_has_feature_extents(fs
->super
)) {
3504 ext2_extent_handle_t handle
;
3506 inode
.i_flags
&= ~EXT4_EXTENTS_FL
;
3507 ret
= ext2fs_extent_open2(fs
, child
,
3508 EXT2_INODE(&inode
), &handle
);
3510 ret
= translate_error(fs
, child
, err
);
3514 ext2fs_extent_free(handle
);
3517 err
= ext2fs_write_new_inode(fs
, child
, EXT2_INODE(&inode
));
3519 ret
= translate_error(fs
, child
, err
);
3523 inode
.i_generation
= ff
->next_generation
++;
3525 err
= fuse2fs_write_inode(fs
, child
, &inode
);
3527 ret
= translate_error(fs
, child
, err
);
3531 ext2fs_inode_alloc_stats2(fs
, child
, 1, 0);
3533 ret
= propagate_default_acls(ff
, parent
, child
);
3537 fp
->flags
&= ~O_TRUNC
;
3538 ret
= __op_open(ff
, path
, fp
);
3542 pthread_mutex_unlock(&ff
->bfl
);
3548 #if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
3549 static int op_ftruncate(const char *path
EXT2FS_ATTR((unused
)),
3550 off_t len
, struct fuse_file_info
*fp
)
3552 struct fuse_context
*ctxt
= fuse_get_context();
3553 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
3554 struct fuse2fs_file_handle
*fh
=
3555 (struct fuse2fs_file_handle
*)(uintptr_t)fp
->fh
;
3561 FUSE2FS_CHECK_CONTEXT(ff
);
3563 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
3564 dbg_printf(ff
, "%s: ino=%d len=%jd\n", __func__
, fh
->ino
,
3566 pthread_mutex_lock(&ff
->bfl
);
3567 if (!fs_writeable(fs
)) {
3572 err
= ext2fs_file_open(fs
, fh
->ino
, fh
->open_flags
, &efp
);
3574 ret
= translate_error(fs
, fh
->ino
, err
);
3578 err
= ext2fs_file_set_size2(efp
, len
);
3580 ret
= translate_error(fs
, fh
->ino
, err
);
3585 err
= ext2fs_file_close(efp
);
3589 ret
= translate_error(fs
, fh
->ino
, err
);
3593 ret
= update_mtime(fs
, fh
->ino
, NULL
);
3598 pthread_mutex_unlock(&ff
->bfl
);
3602 static int op_fgetattr(const char *path
EXT2FS_ATTR((unused
)),
3603 struct stat
*statbuf
,
3604 struct fuse_file_info
*fp
)
3606 struct fuse_context
*ctxt
= fuse_get_context();
3607 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
3609 struct fuse2fs_file_handle
*fh
=
3610 (struct fuse2fs_file_handle
*)(uintptr_t)fp
->fh
;
3613 FUSE2FS_CHECK_CONTEXT(ff
);
3615 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
3616 dbg_printf(ff
, "%s: ino=%d\n", __func__
, fh
->ino
);
3617 pthread_mutex_lock(&ff
->bfl
);
3618 ret
= stat_inode(fs
, fh
->ino
, statbuf
);
3619 pthread_mutex_unlock(&ff
->bfl
);
3623 #endif /* FUSE_VERSION < FUSE_MAKE_VERSION(3, 0) */
3625 static int op_utimens(const char *path
, const struct timespec ctv
[2]
3626 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
3627 , struct fuse_file_info
*fi
EXT2FS_ATTR((unused
))
3631 struct fuse_context
*ctxt
= fuse_get_context();
3632 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
3633 struct timespec tv
[2];
3637 struct ext2_inode_large inode
;
3641 FUSE2FS_CHECK_CONTEXT(ff
);
3643 pthread_mutex_lock(&ff
->bfl
);
3644 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
3646 ret
= translate_error(fs
, 0, err
);
3649 dbg_printf(ff
, "%s: ino=%d atime=%lld.%ld mtime=%lld.%ld\n", __func__
,
3651 (long long int)ctv
[0].tv_sec
, ctv
[0].tv_nsec
,
3652 (long long int)ctv
[1].tv_sec
, ctv
[1].tv_nsec
);
3655 * ext4 allows timestamp updates of append-only files but only if we're
3656 * setting to current time
3658 if (ctv
[0].tv_nsec
== UTIME_NOW
&& ctv
[1].tv_nsec
== UTIME_NOW
)
3660 ret
= check_inum_access(ff
, ino
, access
);
3664 err
= fuse2fs_read_inode(fs
, ino
, &inode
);
3666 ret
= translate_error(fs
, ino
, err
);
3673 if (tv
[0].tv_nsec
== UTIME_NOW
)
3675 if (tv
[1].tv_nsec
== UTIME_NOW
)
3677 #endif /* UTIME_NOW */
3679 if (tv
[0].tv_nsec
!= UTIME_OMIT
)
3680 EXT4_INODE_SET_XTIME(i_atime
, &tv
[0], &inode
);
3681 if (tv
[1].tv_nsec
!= UTIME_OMIT
)
3682 EXT4_INODE_SET_XTIME(i_mtime
, &tv
[1], &inode
);
3683 #endif /* UTIME_OMIT */
3684 ret
= update_ctime(fs
, ino
, &inode
);
3688 err
= fuse2fs_write_inode(fs
, ino
, &inode
);
3690 ret
= translate_error(fs
, ino
, err
);
3695 pthread_mutex_unlock(&ff
->bfl
);
3699 #define FUSE2FS_MODIFIABLE_IFLAGS \
3700 (EXT2_FL_USER_MODIFIABLE & ~(EXT4_EXTENTS_FL | EXT4_CASEFOLD_FL | \
3701 EXT3_JOURNAL_DATA_FL))
3703 static inline int set_iflags(struct ext2_inode_large
*inode
, __u32 iflags
)
3705 if ((inode
->i_flags
^ iflags
) & ~FUSE2FS_MODIFIABLE_IFLAGS
)
3708 inode
->i_flags
= (inode
->i_flags
& ~FUSE2FS_MODIFIABLE_IFLAGS
) |
3709 (iflags
& FUSE2FS_MODIFIABLE_IFLAGS
);
3713 #ifdef SUPPORT_I_FLAGS
3714 static int ioctl_getflags(struct fuse2fs
*ff
, struct fuse2fs_file_handle
*fh
,
3717 ext2_filsys fs
= ff
->fs
;
3719 struct ext2_inode_large inode
;
3721 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
3722 dbg_printf(ff
, "%s: ino=%d\n", __func__
, fh
->ino
);
3723 err
= fuse2fs_read_inode(fs
, fh
->ino
, &inode
);
3725 return translate_error(fs
, fh
->ino
, err
);
3727 *(__u32
*)data
= inode
.i_flags
& EXT2_FL_USER_VISIBLE
;
3731 static int ioctl_setflags(struct fuse2fs
*ff
, struct fuse2fs_file_handle
*fh
,
3734 ext2_filsys fs
= ff
->fs
;
3736 struct ext2_inode_large inode
;
3738 __u32 flags
= *(__u32
*)data
;
3739 struct fuse_context
*ctxt
= fuse_get_context();
3741 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
3742 dbg_printf(ff
, "%s: ino=%d\n", __func__
, fh
->ino
);
3743 err
= fuse2fs_read_inode(fs
, fh
->ino
, &inode
);
3745 return translate_error(fs
, fh
->ino
, err
);
3747 if (want_check_owner(ff
, ctxt
) && inode_uid(inode
) != ctxt
->uid
)
3750 ret
= set_iflags(&inode
, flags
);
3754 ret
= update_ctime(fs
, fh
->ino
, &inode
);
3758 err
= fuse2fs_write_inode(fs
, fh
->ino
, &inode
);
3760 return translate_error(fs
, fh
->ino
, err
);
3765 static int ioctl_getversion(struct fuse2fs
*ff
, struct fuse2fs_file_handle
*fh
,
3768 ext2_filsys fs
= ff
->fs
;
3770 struct ext2_inode_large inode
;
3772 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
3773 dbg_printf(ff
, "%s: ino=%d\n", __func__
, fh
->ino
);
3774 err
= fuse2fs_read_inode(fs
, fh
->ino
, &inode
);
3776 return translate_error(fs
, fh
->ino
, err
);
3778 *(__u32
*)data
= inode
.i_generation
;
3782 static int ioctl_setversion(struct fuse2fs
*ff
, struct fuse2fs_file_handle
*fh
,
3785 ext2_filsys fs
= ff
->fs
;
3787 struct ext2_inode_large inode
;
3789 __u32 generation
= *(__u32
*)data
;
3790 struct fuse_context
*ctxt
= fuse_get_context();
3792 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
3793 dbg_printf(ff
, "%s: ino=%d\n", __func__
, fh
->ino
);
3794 err
= fuse2fs_read_inode(fs
, fh
->ino
, &inode
);
3796 return translate_error(fs
, fh
->ino
, err
);
3798 if (want_check_owner(ff
, ctxt
) && inode_uid(inode
) != ctxt
->uid
)
3801 inode
.i_generation
= generation
;
3803 ret
= update_ctime(fs
, fh
->ino
, &inode
);
3807 err
= fuse2fs_write_inode(fs
, fh
->ino
, &inode
);
3809 return translate_error(fs
, fh
->ino
, err
);
3813 #endif /* SUPPORT_I_FLAGS */
3815 #ifdef FS_IOC_FSGETXATTR
3816 static __u32
iflags_to_fsxflags(__u32 iflags
)
3820 if (iflags
& FS_SYNC_FL
)
3821 xflags
|= FS_XFLAG_SYNC
;
3822 if (iflags
& FS_IMMUTABLE_FL
)
3823 xflags
|= FS_XFLAG_IMMUTABLE
;
3824 if (iflags
& FS_APPEND_FL
)
3825 xflags
|= FS_XFLAG_APPEND
;
3826 if (iflags
& FS_NODUMP_FL
)
3827 xflags
|= FS_XFLAG_NODUMP
;
3828 if (iflags
& FS_NOATIME_FL
)
3829 xflags
|= FS_XFLAG_NOATIME
;
3830 if (iflags
& FS_DAX_FL
)
3831 xflags
|= FS_XFLAG_DAX
;
3832 if (iflags
& FS_PROJINHERIT_FL
)
3833 xflags
|= FS_XFLAG_PROJINHERIT
;
3837 static int ioctl_fsgetxattr(struct fuse2fs
*ff
, struct fuse2fs_file_handle
*fh
,
3840 ext2_filsys fs
= ff
->fs
;
3842 struct ext2_inode_large inode
;
3843 struct fsxattr
*fsx
= data
;
3844 unsigned int inode_size
;
3846 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
3847 dbg_printf(ff
, "%s: ino=%d\n", __func__
, fh
->ino
);
3848 err
= fuse2fs_read_inode(fs
, fh
->ino
, &inode
);
3850 return translate_error(fs
, fh
->ino
, err
);
3852 memset(fsx
, 0, sizeof(*fsx
));
3853 inode_size
= EXT2_GOOD_OLD_INODE_SIZE
+ inode
.i_extra_isize
;
3854 if (ext2fs_inode_includes(inode_size
, i_projid
))
3855 fsx
->fsx_projid
= inode_projid(inode
);
3856 fsx
->fsx_xflags
= iflags_to_fsxflags(inode
.i_flags
);
3860 static __u32
fsxflags_to_iflags(__u32 xflags
)
3864 if (xflags
& FS_XFLAG_IMMUTABLE
)
3865 iflags
|= FS_IMMUTABLE_FL
;
3866 if (xflags
& FS_XFLAG_APPEND
)
3867 iflags
|= FS_APPEND_FL
;
3868 if (xflags
& FS_XFLAG_SYNC
)
3869 iflags
|= FS_SYNC_FL
;
3870 if (xflags
& FS_XFLAG_NOATIME
)
3871 iflags
|= FS_NOATIME_FL
;
3872 if (xflags
& FS_XFLAG_NODUMP
)
3873 iflags
|= FS_NODUMP_FL
;
3874 if (xflags
& FS_XFLAG_DAX
)
3875 iflags
|= FS_DAX_FL
;
3876 if (xflags
& FS_XFLAG_PROJINHERIT
)
3877 iflags
|= FS_PROJINHERIT_FL
;
3881 static int ioctl_fssetxattr(struct fuse2fs
*ff
, struct fuse2fs_file_handle
*fh
,
3884 ext2_filsys fs
= ff
->fs
;
3886 struct ext2_inode_large inode
;
3888 struct fuse_context
*ctxt
= fuse_get_context();
3889 struct fsxattr
*fsx
= data
;
3890 __u32 flags
= fsxflags_to_iflags(fsx
->fsx_xflags
);
3891 unsigned int inode_size
;
3893 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
3894 dbg_printf(ff
, "%s: ino=%d\n", __func__
, fh
->ino
);
3895 err
= fuse2fs_read_inode(fs
, fh
->ino
, &inode
);
3897 return translate_error(fs
, fh
->ino
, err
);
3899 if (want_check_owner(ff
, ctxt
) && inode_uid(inode
) != ctxt
->uid
)
3902 ret
= set_iflags(&inode
, flags
);
3906 inode_size
= EXT2_GOOD_OLD_INODE_SIZE
+ inode
.i_extra_isize
;
3907 if (ext2fs_inode_includes(inode_size
, i_projid
))
3908 inode
.i_projid
= fsx
->fsx_projid
;
3910 ret
= update_ctime(fs
, fh
->ino
, &inode
);
3914 err
= fuse2fs_write_inode(fs
, fh
->ino
, &inode
);
3916 return translate_error(fs
, fh
->ino
, err
);
3920 #endif /* FS_IOC_FSGETXATTR */
3923 static int ioctl_fitrim(struct fuse2fs
*ff
, struct fuse2fs_file_handle
*fh
,
3926 ext2_filsys fs
= ff
->fs
;
3927 struct fstrim_range
*fr
= data
;
3928 blk64_t start
, end
, max_blocks
, b
, cleared
, minlen
;
3929 blk64_t max_blks
= ext2fs_blocks_count(fs
->super
);
3932 if (!fs_writeable(fs
))
3935 start
= FUSE2FS_B_TO_FSBT(ff
, fr
->start
);
3936 if (fr
->len
== -1ULL)
3939 end
= FUSE2FS_B_TO_FSBT(ff
, fr
->start
+ fr
->len
- 1);
3940 minlen
= FUSE2FS_B_TO_FSBT(ff
, fr
->minlen
);
3942 if (EXT2FS_NUM_B2C(fs
, minlen
) > EXT2_CLUSTERS_PER_GROUP(fs
->super
) ||
3943 start
>= max_blks
||
3944 fr
->len
< fs
->blocksize
)
3947 dbg_printf(ff
, "%s: start=%llu end=%llu minlen=%llu\n", __func__
,
3948 start
, end
, minlen
);
3950 if (start
< fs
->super
->s_first_data_block
)
3951 start
= fs
->super
->s_first_data_block
;
3953 if (end
< fs
->super
->s_first_data_block
)
3954 end
= fs
->super
->s_first_data_block
;
3955 if (end
>= ext2fs_blocks_count(fs
->super
))
3956 end
= ext2fs_blocks_count(fs
->super
) - 1;
3959 max_blocks
= FUSE2FS_B_TO_FSBT(ff
, 2048ULL * 1024 * 1024);
3962 while (start
<= end
) {
3963 err
= ext2fs_find_first_zero_block_bitmap2(fs
->block_map
,
3964 start
, end
, &start
);
3969 /* no free blocks found, so we're done */
3973 return translate_error(fs
, fh
->ino
, err
);
3976 b
= start
+ max_blocks
< end
? start
+ max_blocks
: end
;
3977 err
= ext2fs_find_first_set_block_bitmap2(fs
->block_map
,
3979 if (err
&& err
!= ENOENT
)
3980 return translate_error(fs
, fh
->ino
, err
);
3981 if (b
- start
>= minlen
) {
3982 err
= io_channel_discard(fs
->io
, start
, b
- start
);
3984 return translate_error(fs
, fh
->ino
, err
);
3985 cleared
+= b
- start
;
3986 fr
->len
= FUSE2FS_FSB_TO_B(ff
, cleared
);
3992 fr
->len
= FUSE2FS_FSB_TO_B(ff
, cleared
);
3993 dbg_printf(ff
, "%s: len=%llu err=%ld\n", __func__
, fr
->len
, err
);
3998 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
3999 static int op_ioctl(const char *path
EXT2FS_ATTR((unused
)),
4000 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
4005 void *arg
EXT2FS_ATTR((unused
)),
4006 struct fuse_file_info
*fp
,
4007 unsigned int flags
EXT2FS_ATTR((unused
)), void *data
)
4009 struct fuse_context
*ctxt
= fuse_get_context();
4010 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
4011 struct fuse2fs_file_handle
*fh
=
4012 (struct fuse2fs_file_handle
*)(uintptr_t)fp
->fh
;
4015 FUSE2FS_CHECK_CONTEXT(ff
);
4016 pthread_mutex_lock(&ff
->bfl
);
4017 switch ((unsigned long) cmd
) {
4018 #ifdef SUPPORT_I_FLAGS
4019 case EXT2_IOC_GETFLAGS
:
4020 ret
= ioctl_getflags(ff
, fh
, data
);
4022 case EXT2_IOC_SETFLAGS
:
4023 ret
= ioctl_setflags(ff
, fh
, data
);
4025 case EXT2_IOC_GETVERSION
:
4026 ret
= ioctl_getversion(ff
, fh
, data
);
4028 case EXT2_IOC_SETVERSION
:
4029 ret
= ioctl_setversion(ff
, fh
, data
);
4032 #ifdef FS_IOC_FSGETXATTR
4033 case FS_IOC_FSGETXATTR
:
4034 ret
= ioctl_fsgetxattr(ff
, fh
, data
);
4036 case FS_IOC_FSSETXATTR
:
4037 ret
= ioctl_fssetxattr(ff
, fh
, data
);
4042 ret
= ioctl_fitrim(ff
, fh
, data
);
4046 dbg_printf(ff
, "%s: Unknown ioctl %d\n", __func__
, cmd
);
4049 pthread_mutex_unlock(&ff
->bfl
);
4053 #endif /* FUSE 28 */
4055 static int op_bmap(const char *path
, size_t blocksize
EXT2FS_ATTR((unused
)),
4058 struct fuse_context
*ctxt
= fuse_get_context();
4059 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
4065 FUSE2FS_CHECK_CONTEXT(ff
);
4067 pthread_mutex_lock(&ff
->bfl
);
4068 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
4070 ret
= translate_error(fs
, 0, err
);
4073 dbg_printf(ff
, "%s: ino=%d blk=%"PRIu64
"\n", __func__
, ino
, *idx
);
4075 err
= ext2fs_bmap2(fs
, ino
, NULL
, NULL
, 0, *idx
, 0, (blk64_t
*)idx
);
4077 ret
= translate_error(fs
, ino
, err
);
4082 pthread_mutex_unlock(&ff
->bfl
);
4086 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
4087 # ifdef SUPPORT_FALLOCATE
4088 static int fallocate_helper(struct fuse_file_info
*fp
, int mode
, off_t offset
,
4091 struct fuse_context
*ctxt
= fuse_get_context();
4092 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
4093 struct fuse2fs_file_handle
*fh
=
4094 (struct fuse2fs_file_handle
*)(uintptr_t)fp
->fh
;
4096 struct ext2_inode_large inode
;
4102 FUSE2FS_CHECK_CONTEXT(ff
);
4104 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
4105 start
= FUSE2FS_B_TO_FSBT(ff
, offset
);
4106 end
= FUSE2FS_B_TO_FSBT(ff
, offset
+ len
- 1);
4107 dbg_printf(ff
, "%s: ino=%d mode=0x%x start=%llu end=%llu\n", __func__
,
4108 fh
->ino
, mode
, start
, end
);
4109 if (!fs_can_allocate(ff
, FUSE2FS_B_TO_FSB(ff
, len
)))
4112 err
= fuse2fs_read_inode(fs
, fh
->ino
, &inode
);
4115 fsize
= EXT2_I_SIZE(&inode
);
4117 /* Allocate a bunch of blocks */
4118 flags
= (mode
& FL_KEEP_SIZE_FLAG
? 0 :
4119 EXT2_FALLOCATE_INIT_BEYOND_EOF
);
4120 err
= ext2fs_fallocate(fs
, flags
, fh
->ino
,
4122 ~0ULL, start
, end
- start
+ 1);
4123 if (err
&& err
!= EXT2_ET_BLOCK_ALLOC_FAIL
)
4124 return translate_error(fs
, fh
->ino
, err
);
4127 if (!(mode
& FL_KEEP_SIZE_FLAG
)) {
4128 if ((__u64
) offset
+ len
> fsize
) {
4129 err
= ext2fs_inode_size_set(fs
,
4133 return translate_error(fs
, fh
->ino
, err
);
4137 err
= update_mtime(fs
, fh
->ino
, &inode
);
4141 err
= fuse2fs_write_inode(fs
, fh
->ino
, &inode
);
4143 return translate_error(fs
, fh
->ino
, err
);
4148 static errcode_t
clean_block_middle(struct fuse2fs
*ff
, ext2_ino_t ino
,
4149 struct ext2_inode_large
*inode
,
4150 off_t offset
, off_t len
, char **buf
)
4152 ext2_filsys fs
= ff
->fs
;
4154 off_t residue
= FUSE2FS_OFF_IN_FSB(ff
, offset
);
4159 err
= ext2fs_get_mem(fs
->blocksize
, buf
);
4164 err
= ext2fs_bmap2(fs
, ino
, EXT2_INODE(inode
), *buf
, 0,
4165 FUSE2FS_B_TO_FSBT(ff
, offset
), &retflags
, &blk
);
4168 if (!blk
|| (retflags
& BMAP_RET_UNINIT
))
4171 err
= io_channel_read_blk64(fs
->io
, blk
, 1, *buf
);
4175 memset(*buf
+ residue
, 0, len
);
4177 return io_channel_write_blk64(fs
->io
, blk
, 1, *buf
);
4180 static errcode_t
clean_block_edge(struct fuse2fs
*ff
, ext2_ino_t ino
,
4181 struct ext2_inode_large
*inode
, off_t offset
,
4182 int clean_before
, char **buf
)
4184 ext2_filsys fs
= ff
->fs
;
4190 residue
= FUSE2FS_OFF_IN_FSB(ff
, offset
);
4195 err
= ext2fs_get_mem(fs
->blocksize
, buf
);
4200 err
= ext2fs_bmap2(fs
, ino
, EXT2_INODE(inode
), *buf
, 0,
4201 FUSE2FS_B_TO_FSBT(ff
, offset
), &retflags
, &blk
);
4205 err
= io_channel_read_blk64(fs
->io
, blk
, 1, *buf
);
4208 if (!blk
|| (retflags
& BMAP_RET_UNINIT
))
4212 memset(*buf
, 0, residue
);
4214 memset(*buf
+ residue
, 0, fs
->blocksize
- residue
);
4216 return io_channel_write_blk64(fs
->io
, blk
, 1, *buf
);
4219 static int punch_helper(struct fuse_file_info
*fp
, int mode
, off_t offset
,
4222 struct fuse_context
*ctxt
= fuse_get_context();
4223 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
4224 struct fuse2fs_file_handle
*fh
=
4225 (struct fuse2fs_file_handle
*)(uintptr_t)fp
->fh
;
4227 struct ext2_inode_large inode
;
4232 FUSE2FS_CHECK_CONTEXT(ff
);
4234 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
4235 dbg_printf(ff
, "%s: offset=%jd len=%jd\n", __func__
,
4236 (intmax_t) offset
, (intmax_t) len
);
4238 /* kernel ext4 punch requires this flag to be set */
4239 if (!(mode
& FL_KEEP_SIZE_FLAG
))
4243 * Unmap out all full blocks in the middle of the range being punched.
4244 * The start of the unmap range should be the first byte of the first
4245 * fsblock that starts within the range. The end of the range should
4246 * be the next byte after the last fsblock to end in the range.
4248 start
= FUSE2FS_B_TO_FSBT(ff
, round_up(offset
, fs
->blocksize
));
4249 end
= FUSE2FS_B_TO_FSBT(ff
, round_down(offset
+ len
, fs
->blocksize
));
4252 "%s: ino=%d mode=0x%x offset=0x%jx len=0x%jx start=0x%llx end=0x%llx\n",
4253 __func__
, fh
->ino
, mode
, offset
, len
, start
, end
);
4255 err
= fuse2fs_read_inode(fs
, fh
->ino
, &inode
);
4257 return translate_error(fs
, fh
->ino
, err
);
4259 /* Zero everything before the first block and after the last block */
4260 if (FUSE2FS_B_TO_FSBT(ff
, offset
) == FUSE2FS_B_TO_FSBT(ff
, offset
+ len
))
4261 err
= clean_block_middle(ff
, fh
->ino
, &inode
, offset
,
4264 err
= clean_block_edge(ff
, fh
->ino
, &inode
, offset
, 0, &buf
);
4266 err
= clean_block_edge(ff
, fh
->ino
, &inode
,
4267 offset
+ len
, 1, &buf
);
4270 ext2fs_free_mem(&buf
);
4272 return translate_error(fs
, fh
->ino
, err
);
4275 * Unmap full blocks in the middle, which is to say that start - end
4276 * must be at least one fsblock. ext2fs_punch takes a closed interval
4277 * as its argument, so we pass [start, end - 1].
4280 err
= ext2fs_punch(fs
, fh
->ino
, EXT2_INODE(&inode
),
4281 NULL
, start
, end
- 1);
4283 return translate_error(fs
, fh
->ino
, err
);
4286 err
= update_mtime(fs
, fh
->ino
, &inode
);
4290 err
= fuse2fs_write_inode(fs
, fh
->ino
, &inode
);
4292 return translate_error(fs
, fh
->ino
, err
);
4297 static int zero_helper(struct fuse_file_info
*fp
, int mode
, off_t offset
,
4300 int ret
= punch_helper(fp
, mode
| FL_KEEP_SIZE_FLAG
, offset
, len
);
4303 ret
= fallocate_helper(fp
, mode
, offset
, len
);
4307 static int op_fallocate(const char *path
EXT2FS_ATTR((unused
)), int mode
,
4308 off_t offset
, off_t len
,
4309 struct fuse_file_info
*fp
)
4311 struct fuse_context
*ctxt
= fuse_get_context();
4312 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
4313 ext2_filsys fs
= ff
->fs
;
4316 /* Catch unknown flags */
4317 if (mode
& ~(FL_ZERO_RANGE_FLAG
| FL_PUNCH_HOLE_FLAG
| FL_KEEP_SIZE_FLAG
))
4320 pthread_mutex_lock(&ff
->bfl
);
4321 if (!fs_writeable(fs
)) {
4325 if (mode
& FL_ZERO_RANGE_FLAG
)
4326 ret
= zero_helper(fp
, mode
, offset
, len
);
4327 else if (mode
& FL_PUNCH_HOLE_FLAG
)
4328 ret
= punch_helper(fp
, mode
, offset
, len
);
4330 ret
= fallocate_helper(fp
, mode
, offset
, len
);
4332 pthread_mutex_unlock(&ff
->bfl
);
4336 # endif /* SUPPORT_FALLOCATE */
4337 #endif /* FUSE 29 */
4339 static struct fuse_operations fs_ops
= {
4341 .destroy
= op_destroy
,
4342 .getattr
= op_getattr
,
4343 .readlink
= op_readlink
,
4346 .unlink
= op_unlink
,
4348 .symlink
= op_symlink
,
4349 .rename
= op_rename
,
4353 .truncate
= op_truncate
,
4357 .statfs
= op_statfs
,
4358 .release
= op_release
,
4360 .setxattr
= op_setxattr
,
4361 .getxattr
= op_getxattr
,
4362 .listxattr
= op_listxattr
,
4363 .removexattr
= op_removexattr
,
4365 .readdir
= op_readdir
,
4366 .releasedir
= op_release
,
4367 .fsyncdir
= op_fsync
,
4368 .access
= op_access
,
4369 .create
= op_create
,
4370 #if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
4371 .ftruncate
= op_ftruncate
,
4372 .fgetattr
= op_fgetattr
,
4374 .utimens
= op_utimens
,
4375 #if (FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)) && (FUSE_VERSION < FUSE_MAKE_VERSION(3, 0))
4376 # if defined(UTIME_NOW) || defined(UTIME_OMIT)
4377 .flag_utime_omit_ok
= 1,
4385 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
4387 #if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
4388 .flag_nullpath_ok
= 1,
4391 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
4392 #if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
4395 # ifdef SUPPORT_FALLOCATE
4396 .fallocate
= op_fallocate
,
4401 static int get_random_bytes(void *p
, size_t sz
)
4406 fd
= open("/dev/urandom", O_RDONLY
);
4408 perror("/dev/urandom");
4412 r
= read(fd
, p
, sz
);
4415 return (size_t) r
== sz
;
4426 #define FUSE2FS_OPT(t, p, v) { t, offsetof(struct fuse2fs, p), v }
4428 static struct fuse_opt fuse2fs_opts
[] = {
4429 FUSE2FS_OPT("ro", ro
, 1),
4430 FUSE2FS_OPT("rw", ro
, 0),
4431 FUSE2FS_OPT("errors=panic", panic_on_error
, 1),
4432 FUSE2FS_OPT("minixdf", minixdf
, 1),
4433 FUSE2FS_OPT("bsddf", minixdf
, 0),
4434 FUSE2FS_OPT("fakeroot", fakeroot
, 1),
4435 FUSE2FS_OPT("fuse2fs_debug", debug
, 1),
4436 FUSE2FS_OPT("no_default_opts", no_default_opts
, 1),
4437 FUSE2FS_OPT("norecovery", norecovery
, 1),
4438 FUSE2FS_OPT("noload", norecovery
, 1),
4439 FUSE2FS_OPT("offset=%lu", offset
, 0),
4440 FUSE2FS_OPT("kernel", kernel
, 1),
4441 FUSE2FS_OPT("directio", directio
, 1),
4442 FUSE2FS_OPT("acl", acl
, 1),
4443 FUSE2FS_OPT("noacl", acl
, 0),
4445 FUSE_OPT_KEY("user_xattr", FUSE2FS_IGNORED
),
4446 FUSE_OPT_KEY("noblock_validity", FUSE2FS_IGNORED
),
4447 FUSE_OPT_KEY("nodelalloc", FUSE2FS_IGNORED
),
4448 FUSE_OPT_KEY("cache_size=%s", FUSE2FS_CACHE_SIZE
),
4449 FUSE2FS_OPT("lockfile=%s", lockfile
, 0),
4451 FUSE_OPT_KEY("-V", FUSE2FS_VERSION
),
4452 FUSE_OPT_KEY("--version", FUSE2FS_VERSION
),
4453 FUSE_OPT_KEY("-h", FUSE2FS_HELP
),
4454 FUSE_OPT_KEY("--help", FUSE2FS_HELP
),
4455 FUSE_OPT_KEY("--helpfull", FUSE2FS_HELPFULL
),
4460 static int fuse2fs_opt_proc(void *data
, const char *arg
,
4461 int key
, struct fuse_args
*outargs
)
4463 struct fuse2fs
*ff
= data
;
4466 case FUSE_OPT_KEY_NONOPT
:
4468 ff
->device
= strdup(arg
);
4472 case FUSE2FS_CACHE_SIZE
:
4473 ff
->cache_size
= parse_num_blocks2(arg
+ 11, -1);
4474 if (ff
->cache_size
< 1 || ff
->cache_size
> INT32_MAX
) {
4475 fprintf(stderr
, "%s: %s\n", arg
,
4476 _("cache size must be between 1 block and 2GB."));
4480 /* do not pass through to libfuse */
4482 case FUSE2FS_IGNORED
:
4485 case FUSE2FS_HELPFULL
:
4487 "usage: %s device/image mountpoint [options]\n"
4489 "general options:\n"
4490 " -o opt,[opt...] mount options\n"
4491 " -h --help print help\n"
4492 " -V --version print version\n"
4494 "fuse2fs options:\n"
4495 " -o errors=panic dump core on error\n"
4496 " -o minixdf minix-style df\n"
4497 " -o fakeroot pretend to be root for permission checks\n"
4498 " -o no_default_opts do not include default fuse options\n"
4499 " -o offset=<bytes> similar to mount -o offset=<bytes>, mount the partition starting at <bytes>\n"
4500 " -o norecovery don't replay the journal\n"
4501 " -o fuse2fs_debug enable fuse2fs debugging\n"
4502 " -o lockfile=<file> file to show that fuse is still using the file system image\n"
4503 " -o kernel run this as if it were the kernel, which sets:\n"
4504 " allow_others,default_permissions,suid,dev\n"
4505 " -o directio use O_DIRECT to read and write the disk\n"
4506 " -o cache_size=N[KMG] use a disk cache of this size\n"
4509 if (key
== FUSE2FS_HELPFULL
) {
4510 fuse_opt_add_arg(outargs
, "-h");
4511 fuse_main(outargs
->argc
, outargs
->argv
, &fs_ops
, NULL
);
4513 fprintf(stderr
, "Try --helpfull to get a list of "
4514 "all flags, including the FUSE options.\n");
4518 case FUSE2FS_VERSION
:
4519 fprintf(stderr
, "fuse2fs %s (%s)\n", E2FSPROGS_VERSION
,
4521 fuse_opt_add_arg(outargs
, "--version");
4522 fuse_main(outargs
->argc
, outargs
->argv
, &fs_ops
, NULL
);
4528 static const char *get_subtype(const char *argv0
)
4530 size_t argvlen
= strlen(argv0
);
4535 if (argv0
[argvlen
- 4] == 'e' &&
4536 argv0
[argvlen
- 3] == 'x' &&
4537 argv0
[argvlen
- 2] == 't' &&
4538 isdigit(argv0
[argvlen
- 1]))
4539 return &argv0
[argvlen
- 4];
4545 /* Figure out a reasonable default size for the disk cache */
4546 static unsigned long long default_cache_size(void)
4548 long pages
= 0, pagesize
= 0;
4549 unsigned long long max_cache
;
4550 unsigned long long ret
= 32ULL << 20; /* 32 MB */
4552 #ifdef _SC_PHYS_PAGES
4553 pages
= sysconf(_SC_PHYS_PAGES
);
4556 pagesize
= sysconf(_SC_PAGESIZE
);
4558 if (pages
> 0 && pagesize
> 0) {
4559 max_cache
= (unsigned long long)pagesize
* pages
/ 20;
4561 if (max_cache
> 0 && ret
> max_cache
)
4567 int main(int argc
, char *argv
[])
4569 struct fuse_args args
= FUSE_ARGS_INIT(argc
, argv
);
4570 struct fuse2fs fctx
;
4572 FILE *orig_stderr
= stderr
;
4573 char extra_args
[BUFSIZ
];
4575 int flags
= EXT2_FLAG_64BITS
| EXT2_FLAG_THREADS
| EXT2_FLAG_EXCLUSIVE
|
4578 memset(&fctx
, 0, sizeof(fctx
));
4579 fctx
.magic
= FUSE2FS_MAGIC
;
4582 ret
= fuse_opt_parse(&args
, &fctx
, fuse2fs_opts
, fuse2fs_opt_proc
);
4585 if (fctx
.device
== NULL
) {
4586 fprintf(stderr
, "Missing ext4 device/image\n");
4587 fprintf(stderr
, "See '%s -h' for usage\n", argv
[0]);
4591 /* /dev/sda -> sda for reporting */
4592 fctx
.shortdev
= strrchr(fctx
.device
, '/');
4596 fctx
.shortdev
= fctx
.device
;
4599 setlocale(LC_MESSAGES
, "");
4600 setlocale(LC_CTYPE
, "");
4601 bindtextdomain(NLS_CAT_NAME
, LOCALEDIR
);
4602 textdomain(NLS_CAT_NAME
);
4603 set_com_err_gettext(gettext
);
4605 add_error_table(&et_ext2_error_table
);
4607 ret
= fuse2fs_setup_logging(&fctx
);
4609 /* operational error */
4614 /* Will we allow users to allocate every last block? */
4615 if (getenv("FUSE2FS_ALLOC_ALL_BLOCKS")) {
4616 log_printf(&fctx
, "%s\n",
4617 _("Allowing users to allocate all blocks. This is dangerous!"));
4618 fctx
.alloc_all_blocks
= 1;
4621 if (fctx
.lockfile
) {
4625 lockfd
= open(fctx
.lockfile
, O_RDWR
| O_CREAT
| O_EXCL
, 0400);
4627 if (errno
== EEXIST
)
4631 err_printf(&fctx
, "%s: %s: %s\n", fctx
.lockfile
,
4632 _("opening lockfile failed"),
4634 fctx
.lockfile
= NULL
;
4640 resolved
= realpath(fctx
.lockfile
, NULL
);
4643 err_printf(&fctx
, "%s: %s: %s\n", fctx
.lockfile
,
4644 _("resolving lockfile failed"),
4646 unlink(fctx
.lockfile
);
4647 fctx
.lockfile
= NULL
;
4651 free(fctx
.lockfile
);
4652 fctx
.lockfile
= resolved
;
4655 /* Start up the fs (while we still can use stdout) */
4658 sprintf(options
, "offset=%lu", fctx
.offset
);
4660 flags
|= EXT2_FLAG_DIRECT_IO
;
4661 err
= ext2fs_open2(fctx
.device
, options
, flags
, 0, 0, unix_io_manager
,
4664 err_printf(&fctx
, "%s.\n", error_message(err
));
4665 err_printf(&fctx
, "%s\n", _("Please run e2fsck -fy."));
4668 fctx
.fs
= global_fs
;
4669 global_fs
->priv_data
= &fctx
;
4670 fctx
.blocklog
= u_log2(fctx
.fs
->blocksize
);
4671 fctx
.blockmask
= fctx
.fs
->blocksize
- 1;
4673 if (!fctx
.cache_size
)
4674 fctx
.cache_size
= default_cache_size();
4675 if (fctx
.cache_size
) {
4678 snprintf(buf
, sizeof(buf
), "cache_blocks=%llu",
4679 FUSE2FS_B_TO_FSBT(&fctx
, fctx
.cache_size
));
4680 err
= io_channel_set_options(global_fs
->io
, buf
);
4682 err_printf(&fctx
, "%s %lluk: %s\n",
4683 _("cannot set disk cache size to"),
4684 fctx
.cache_size
>> 10,
4685 error_message(err
));
4692 if (ext2fs_has_feature_quota(global_fs
->super
)) {
4693 err_printf(&fctx
, "%s", _("quotas not supported."));
4696 if (ext2fs_has_feature_verity(global_fs
->super
)) {
4697 err_printf(&fctx
, "%s", _("verity not supported."));
4700 if (ext2fs_has_feature_encrypt(global_fs
->super
)) {
4701 err_printf(&fctx
, "%s", _("encryption not supported."));
4704 if (ext2fs_has_feature_casefold(global_fs
->super
)) {
4705 err_printf(&fctx
, "%s", _("casefolding not supported."));
4709 if (ext2fs_has_feature_shared_blocks(global_fs
->super
))
4712 if (ext2fs_has_feature_journal_needs_recovery(global_fs
->super
)) {
4713 if (fctx
.norecovery
) {
4714 log_printf(&fctx
, "%s\n",
4715 _("Mounting read-only without recovering journal."));
4717 global_fs
->flags
&= ~EXT2_FLAG_RW
;
4719 log_printf(&fctx
, "%s\n", _("Recovering journal."));
4720 err
= ext2fs_run_ext3_journal(&global_fs
);
4722 err_printf(&fctx
, "%s.\n", error_message(err
));
4723 err_printf(&fctx
, "%s\n",
4724 _("Please run e2fsck -fy."));
4727 ext2fs_clear_feature_journal_needs_recovery(global_fs
->super
);
4728 ext2fs_mark_super_dirty(global_fs
);
4732 if (global_fs
->flags
& EXT2_FLAG_RW
) {
4733 if (ext2fs_has_feature_journal(global_fs
->super
))
4734 log_printf(&fctx
, "%s",
4735 _("Warning: fuse2fs does not support using the journal.\n"
4736 "There may be file system corruption or data loss if\n"
4737 "the file system is not gracefully unmounted.\n"));
4738 err
= ext2fs_read_inode_bitmap(global_fs
);
4740 translate_error(global_fs
, 0, err
);
4743 err
= ext2fs_read_block_bitmap(global_fs
);
4745 translate_error(global_fs
, 0, err
);
4750 if (!(global_fs
->super
->s_state
& EXT2_VALID_FS
))
4751 err_printf(&fctx
, "%s\n",
4752 _("Warning: Mounting unchecked fs, running e2fsck is recommended."));
4753 if (global_fs
->super
->s_max_mnt_count
> 0 &&
4754 global_fs
->super
->s_mnt_count
>= global_fs
->super
->s_max_mnt_count
)
4755 err_printf(&fctx
, "%s\n",
4756 _("Warning: Maximal mount count reached, running e2fsck is recommended."));
4757 if (global_fs
->super
->s_checkinterval
> 0 &&
4758 (time_t) (global_fs
->super
->s_lastcheck
+
4759 global_fs
->super
->s_checkinterval
) <= time(0))
4760 err_printf(&fctx
, "%s\n",
4761 _("Warning: Check time reached; running e2fsck is recommended."));
4762 if (global_fs
->super
->s_last_orphan
)
4763 err_printf(&fctx
, "%s\n",
4764 _("Orphans detected; running e2fsck is recommended."));
4766 if (global_fs
->super
->s_state
& EXT2_ERROR_FS
) {
4767 err_printf(&fctx
, "%s\n",
4768 _("Errors detected; running e2fsck is required."));
4772 /* Initialize generation counter */
4773 get_random_bytes(&fctx
.next_generation
, sizeof(unsigned int));
4775 /* Set up default fuse parameters */
4776 snprintf(extra_args
, BUFSIZ
, "-okernel_cache,subtype=%s,"
4777 "fsname=%s,attr_timeout=0" FUSE_PLATFORM_OPTS
,
4778 get_subtype(argv
[0]),
4780 if (fctx
.no_default_opts
== 0)
4781 fuse_opt_add_arg(&args
, extra_args
);
4784 fuse_opt_add_arg(&args
, "-oro");
4786 if (fctx
.fakeroot
) {
4787 #ifdef HAVE_MOUNT_NODEV
4788 fuse_opt_add_arg(&args
,"-onodev");
4790 #ifdef HAVE_MOUNT_NOSUID
4791 fuse_opt_add_arg(&args
,"-onosuid");
4797 * ACLs are always enforced when kernel mode is enabled, to
4798 * match the kernel ext4 driver which always enables ACLs.
4801 fuse_opt_insert_arg(&args
, 1,
4802 "-oallow_other,default_permissions,suid,dev");
4808 printf("FUSE2FS (%s): fuse arguments:", fctx
.shortdev
);
4809 for (i
= 0; i
< args
.argc
; i
++)
4810 printf(" '%s'", args
.argv
[i
]);
4815 pthread_mutex_init(&fctx
.bfl
, NULL
);
4816 ret
= fuse_main(args
.argc
, args
.argv
, &fs_ops
, &fctx
);
4817 pthread_mutex_destroy(&fctx
.bfl
);
4826 /* invalid option or no mountpoint */
4834 /* setup or mounting failed */
4838 /* fuse started up enough to call op_init */
4844 fprintf(orig_stderr
, "%s\n",
4845 _("Mount failed due to unrecognized options. Check dmesg(1) for details."));
4846 fflush(orig_stderr
);
4849 fprintf(orig_stderr
, "%s\n",
4850 _("Mount failed while opening filesystem. Check dmesg(1) for details."));
4851 fflush(orig_stderr
);
4854 err
= ext2fs_close(global_fs
);
4856 com_err(argv
[0], err
, "while closing fs");
4859 if (fctx
.lockfile
) {
4860 if (unlink(fctx
.lockfile
)) {
4862 err_printf(&fctx
, "%s: %s: %s\n", fctx
.lockfile
,
4863 _("removing lockfile failed"),
4866 free(fctx
.lockfile
);
4870 fuse_opt_free_args(&args
);
4874 static int __translate_error(ext2_filsys fs
, ext2_ino_t ino
, errcode_t err
,
4875 const char *file
, int line
)
4877 struct timespec now
;
4879 struct fuse2fs
*ff
= fs
->priv_data
;
4882 /* Translate ext2 error to unix error code */
4886 case EXT2_ET_NO_MEMORY
:
4887 case EXT2_ET_TDB_ERR_OOM
:
4890 case EXT2_ET_INVALID_ARGUMENT
:
4891 case EXT2_ET_LLSEEK_FAILED
:
4894 case EXT2_ET_NO_DIRECTORY
:
4897 case EXT2_ET_FILE_NOT_FOUND
:
4900 case EXT2_ET_DIR_NO_SPACE
:
4903 case EXT2_ET_TOOSMALL
:
4904 case EXT2_ET_BLOCK_ALLOC_FAIL
:
4905 case EXT2_ET_INODE_ALLOC_FAIL
:
4906 case EXT2_ET_EA_NO_SPACE
:
4909 case EXT2_ET_SYMLINK_LOOP
:
4912 case EXT2_ET_FILE_TOO_BIG
:
4915 case EXT2_ET_TDB_ERR_EXISTS
:
4916 case EXT2_ET_FILE_EXISTS
:
4919 case EXT2_ET_MMP_FAILED
:
4920 case EXT2_ET_MMP_FSCK_ON
:
4923 case EXT2_ET_EA_KEY_NOT_FOUND
:
4926 /* Sometimes fuse returns a garbage file handle pointer to us... */
4927 case EXT2_ET_MAGIC_EXT2_FILE
:
4930 case EXT2_ET_UNIMPLEMENTED
:
4933 case EXT2_ET_MAGIC_EXT2FS_FILSYS
:
4934 case EXT2_ET_MAGIC_BADBLOCKS_LIST
:
4935 case EXT2_ET_MAGIC_BADBLOCKS_ITERATE
:
4936 case EXT2_ET_MAGIC_INODE_SCAN
:
4937 case EXT2_ET_MAGIC_IO_CHANNEL
:
4938 case EXT2_ET_MAGIC_UNIX_IO_CHANNEL
:
4939 case EXT2_ET_MAGIC_IO_MANAGER
:
4940 case EXT2_ET_MAGIC_BLOCK_BITMAP
:
4941 case EXT2_ET_MAGIC_INODE_BITMAP
:
4942 case EXT2_ET_MAGIC_GENERIC_BITMAP
:
4943 case EXT2_ET_MAGIC_TEST_IO_CHANNEL
:
4944 case EXT2_ET_MAGIC_DBLIST
:
4945 case EXT2_ET_MAGIC_ICOUNT
:
4946 case EXT2_ET_MAGIC_PQ_IO_CHANNEL
:
4947 case EXT2_ET_MAGIC_E2IMAGE
:
4948 case EXT2_ET_MAGIC_INODE_IO_CHANNEL
:
4949 case EXT2_ET_MAGIC_EXTENT_HANDLE
:
4950 case EXT2_ET_BAD_MAGIC
:
4951 case EXT2_ET_MAGIC_EXTENT_PATH
:
4952 case EXT2_ET_MAGIC_GENERIC_BITMAP64
:
4953 case EXT2_ET_MAGIC_BLOCK_BITMAP64
:
4954 case EXT2_ET_MAGIC_INODE_BITMAP64
:
4955 case EXT2_ET_MAGIC_RESERVED_13
:
4956 case EXT2_ET_MAGIC_RESERVED_14
:
4957 case EXT2_ET_MAGIC_RESERVED_15
:
4958 case EXT2_ET_MAGIC_RESERVED_16
:
4959 case EXT2_ET_MAGIC_RESERVED_17
:
4960 case EXT2_ET_MAGIC_RESERVED_18
:
4961 case EXT2_ET_MAGIC_RESERVED_19
:
4962 case EXT2_ET_MMP_MAGIC_INVALID
:
4963 case EXT2_ET_MAGIC_EA_HANDLE
:
4964 case EXT2_ET_DIR_CORRUPTED
:
4965 case EXT2_ET_CORRUPT_SUPERBLOCK
:
4966 case EXT2_ET_RESIZE_INODE_CORRUPT
:
4967 case EXT2_ET_TDB_ERR_CORRUPT
:
4968 case EXT2_ET_UNDO_FILE_CORRUPT
:
4969 case EXT2_ET_FILESYSTEM_CORRUPTED
:
4970 case EXT2_ET_CORRUPT_JOURNAL_SB
:
4971 case EXT2_ET_INODE_CORRUPTED
:
4972 case EXT2_ET_EA_INODE_CORRUPTED
:
4973 /* same errno that linux uses */
4982 /* these errnos usually denote corruption or persistence fail */
4988 /* other errno are usually operational errors */
5001 err_printf(ff
, "%s (inode #%d) at %s:%d.\n",
5002 error_message(err
), ino
, file
, line
);
5004 err_printf(ff
, "%s at %s:%d.\n",
5005 error_message(err
), file
, line
);
5007 /* Make a note in the error log */
5009 ext2fs_set_tstamp(fs
->super
, s_last_error_time
, now
.tv_sec
);
5010 fs
->super
->s_last_error_ino
= ino
;
5011 fs
->super
->s_last_error_line
= line
;
5012 fs
->super
->s_last_error_block
= err
; /* Yeah... */
5013 strncpy((char *)fs
->super
->s_last_error_func
, file
,
5014 sizeof(fs
->super
->s_last_error_func
));
5015 if (ext2fs_get_tstamp(fs
->super
, s_first_error_time
) == 0) {
5016 ext2fs_set_tstamp(fs
->super
, s_first_error_time
, now
.tv_sec
);
5017 fs
->super
->s_first_error_ino
= ino
;
5018 fs
->super
->s_first_error_line
= line
;
5019 fs
->super
->s_first_error_block
= err
;
5020 strncpy((char *)fs
->super
->s_first_error_func
, file
,
5021 sizeof(fs
->super
->s_first_error_func
));
5024 fs
->super
->s_error_count
++;
5025 ext2fs_mark_super_dirty(fs
);
5027 if (ff
->panic_on_error
)