2 * fuse2fs.c - FUSE server for e2fsprogs.
4 * Copyright (C) 2014 Oracle.
7 * This file may be redistributed under the terms of the GNU Public
11 #define _FILE_OFFSET_BITS 64
12 #define FUSE_USE_VERSION 29
17 # include <linux/fs.h>
18 # include <linux/falloc.h>
19 # include <linux/xattr.h>
20 # define FUSE_PLATFORM_OPTS ",nonempty,big_writes"
21 # ifdef HAVE_SYS_ACL_H
22 # define TRANSLATE_LINUX_ACLS
25 # define FUSE_PLATFORM_OPTS ""
27 #ifdef TRANSLATE_LINUX_ACLS
30 #include <sys/ioctl.h>
34 #include "ext2fs/ext2fs.h"
35 #include "ext2fs/ext2_fs.h"
40 #define _(a) (gettext(a))
42 #define N_(a) gettext_noop(a)
46 #define P_(singular, plural, n) (ngettext(singular, plural, n))
48 #define NLS_CAT_NAME "e2fsprogs"
51 #define LOCALEDIR "/usr/share/locale"
56 #define P_(singular, plural, n) ((n) == 1 ? (singular) : (plural))
59 static ext2_filsys global_fs
; /* Try not to use this directly */
64 # define dbg_printf(f, a...) do {printf("FUSE2FS-" f, ## a); \
68 # define dbg_printf(f, a...)
71 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
74 # define SUPPORT_I_FLAGS
79 #ifdef FALLOC_FL_KEEP_SIZE
80 # define FL_KEEP_SIZE_FLAG FALLOC_FL_KEEP_SIZE
81 # define SUPPORT_FALLOCATE
83 # define FL_KEEP_SIZE_FLAG (0)
86 #ifdef FALLOC_FL_PUNCH_HOLE
87 # define FL_PUNCH_HOLE_FLAG FALLOC_FL_PUNCH_HOLE
89 # define FL_PUNCH_HOLE_FLAG (0)
92 errcode_t
ext2fs_run_ext3_journal(ext2_filsys
*fs
);
94 /* ACL translation stuff */
95 #ifdef TRANSLATE_LINUX_ACLS
97 * Copied from acl_ea.h in libacl source; ACLs have to be sent to and from fuse
98 * in this format... at least on Linux.
100 #define ACL_EA_ACCESS "system.posix_acl_access"
101 #define ACL_EA_DEFAULT "system.posix_acl_default"
103 #define ACL_EA_VERSION 0x0002
113 acl_ea_entry a_entries
[0];
116 static inline size_t acl_ea_size(int count
)
118 return sizeof(acl_ea_header
) + count
* sizeof(acl_ea_entry
);
121 static inline int acl_ea_count(size_t size
)
123 if (size
< sizeof(acl_ea_header
))
125 size
-= sizeof(acl_ea_header
);
126 if (size
% sizeof(acl_ea_entry
))
128 return size
/ sizeof(acl_ea_entry
);
132 * ext4 ACL structures, copied from fs/ext4/acl.h.
134 #define EXT4_ACL_VERSION 0x0001
145 } ext4_acl_entry_short
;
151 static inline size_t ext4_acl_size(int count
)
154 return sizeof(ext4_acl_header
) +
155 count
* sizeof(ext4_acl_entry_short
);
157 return sizeof(ext4_acl_header
) +
158 4 * sizeof(ext4_acl_entry_short
) +
159 (count
- 4) * sizeof(ext4_acl_entry
);
163 static inline int ext4_acl_count(size_t size
)
167 size
-= sizeof(ext4_acl_header
);
168 s
= size
- 4 * sizeof(ext4_acl_entry_short
);
170 if (size
% sizeof(ext4_acl_entry_short
))
172 return size
/ sizeof(ext4_acl_entry_short
);
174 if (s
% sizeof(ext4_acl_entry
))
176 return s
/ sizeof(ext4_acl_entry
) + 4;
179 static errcode_t
fuse_to_ext4_acl(acl_ea_header
*facl
, size_t facl_sz
,
180 ext4_acl_header
**eacl
, size_t *eacl_sz
)
190 facl_count
= acl_ea_count(facl_sz
);
191 h_sz
= ext4_acl_size(facl_count
);
192 if (facl_count
< 0 || facl
->a_version
!= ACL_EA_VERSION
)
193 return EXT2_ET_INVALID_ARGUMENT
;
195 err
= ext2fs_get_mem(h_sz
, &h
);
199 h
->a_version
= ext2fs_cpu_to_le32(EXT4_ACL_VERSION
);
201 for (i
= 0, a
= facl
->a_entries
; i
< facl_count
; i
++, a
++) {
203 e
->e_tag
= ext2fs_cpu_to_le16(a
->e_tag
);
204 e
->e_perm
= ext2fs_cpu_to_le16(a
->e_perm
);
209 e
->e_id
= ext2fs_cpu_to_le32(a
->e_id
);
210 hptr
+= sizeof(ext4_acl_entry
);
216 hptr
+= sizeof(ext4_acl_entry_short
);
219 err
= EXT2_ET_INVALID_ARGUMENT
;
232 static errcode_t
ext4_to_fuse_acl(acl_ea_header
**facl
, size_t *facl_sz
,
233 ext4_acl_header
*eacl
, size_t eacl_sz
)
243 eacl_count
= ext4_acl_count(eacl_sz
);
244 f_sz
= acl_ea_size(eacl_count
);
245 if (eacl_count
< 0 ||
246 eacl
->a_version
!= ext2fs_cpu_to_le32(EXT4_ACL_VERSION
))
247 return EXT2_ET_INVALID_ARGUMENT
;
249 err
= ext2fs_get_mem(f_sz
, &f
);
253 f
->a_version
= ACL_EA_VERSION
;
255 for (i
= 0, a
= f
->a_entries
; i
< eacl_count
; i
++, a
++) {
257 a
->e_tag
= ext2fs_le16_to_cpu(e
->e_tag
);
258 a
->e_perm
= ext2fs_le16_to_cpu(e
->e_perm
);
263 a
->e_id
= ext2fs_le32_to_cpu(e
->e_id
);
264 hptr
+= sizeof(ext4_acl_entry
);
270 hptr
+= sizeof(ext4_acl_entry_short
);
273 err
= EXT2_ET_INVALID_ARGUMENT
;
285 #endif /* TRANSLATE_LINUX_ACLS */
288 * ext2_file_t contains a struct inode, so we can't leave files open.
289 * Use this as a proxy instead.
291 #define FUSE2FS_FILE_MAGIC (0xEF53DEAFUL)
292 struct fuse2fs_file_handle
{
298 /* Main program context */
299 #define FUSE2FS_MAGIC (0xEF53DEADUL)
306 int alloc_all_blocks
;
308 unsigned int next_generation
;
311 #define FUSE2FS_CHECK_MAGIC(fs, ptr, num) do {if ((ptr)->magic != (num)) \
312 return translate_error((fs), 0, EXT2_ET_MAGIC_EXT2_FILE); \
315 #define FUSE2FS_CHECK_CONTEXT(ptr) do {if ((ptr)->magic != FUSE2FS_MAGIC) \
316 return translate_error(global_fs, 0, EXT2_ET_BAD_MAGIC); \
319 static int __translate_error(ext2_filsys fs
, errcode_t err
, ext2_ino_t ino
,
320 const char *file
, int line
);
321 #define translate_error(fs, ino, err) __translate_error((fs), (err), (ino), \
333 #define EXT4_EPOCH_BITS 2
334 #define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1)
335 #define EXT4_NSEC_MASK (~0UL << EXT4_EPOCH_BITS)
338 * Extended fields will fit into an inode if the filesystem was formatted
339 * with large inodes (-I 256 or larger) and there are not currently any EAs
340 * consuming all of the available space. For new inodes we always reserve
341 * enough space for the kernel's known extended fields, but for inodes
342 * created with an old kernel this might not have been the case. None of
343 * the extended inode fields is critical for correct filesystem operation.
344 * This macro checks if a certain field fits in the inode. Note that
345 * inode-size = GOOD_OLD_INODE_SIZE + i_extra_isize
347 #define EXT4_FITS_IN_INODE(ext4_inode, field) \
348 ((offsetof(typeof(*ext4_inode), field) + \
349 sizeof((ext4_inode)->field)) \
350 <= (EXT2_GOOD_OLD_INODE_SIZE + \
351 (ext4_inode)->i_extra_isize)) \
353 static inline __u32 ext4_encode_extra_time(const struct timespec *time)
355 __u32 extra
= sizeof(time
->tv_sec
) > 4 ?
356 ((time
->tv_sec
- (__s32
)time
->tv_sec
) >> 32) &
358 return extra
| (time
->tv_nsec
<< EXT4_EPOCH_BITS
);
361 static inline void ext4_decode_extra_time(struct timespec
*time
, __u32 extra
)
363 if (sizeof(time
->tv_sec
) > 4 && (extra
& EXT4_EPOCH_MASK
)) {
364 __u64 extra_bits
= extra
& EXT4_EPOCH_MASK
;
366 * Prior to kernel 3.14?, we had a broken decode function,
367 * wherein we effectively did this:
368 * if (extra_bits == 3)
371 time
->tv_sec
+= extra_bits
<< 32;
373 time
->tv_nsec
= ((extra
) & EXT4_NSEC_MASK
) >> EXT4_EPOCH_BITS
;
376 #define EXT4_INODE_SET_XTIME(xtime, timespec, raw_inode) \
378 (raw_inode)->xtime = (timespec)->tv_sec; \
379 if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \
380 (raw_inode)->xtime ## _extra = \
381 ext4_encode_extra_time(timespec); \
384 #define EXT4_EINODE_SET_XTIME(xtime, timespec, raw_inode) \
386 if (EXT4_FITS_IN_INODE(raw_inode, xtime)) \
387 (raw_inode)->xtime = (timespec)->tv_sec; \
388 if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \
389 (raw_inode)->xtime ## _extra = \
390 ext4_encode_extra_time(timespec); \
393 #define EXT4_INODE_GET_XTIME(xtime, timespec, raw_inode) \
395 (timespec)->tv_sec = (signed)((raw_inode)->xtime); \
396 if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \
397 ext4_decode_extra_time((timespec), \
398 (raw_inode)->xtime ## _extra); \
400 (timespec)->tv_nsec = 0; \
403 #define EXT4_EINODE_GET_XTIME(xtime, timespec, raw_inode) \
405 if (EXT4_FITS_IN_INODE(raw_inode, xtime)) \
406 (timespec)->tv_sec = \
407 (signed)((raw_inode)->xtime); \
408 if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \
409 ext4_decode_extra_time((timespec), \
410 raw_inode->xtime ## _extra); \
412 (timespec)->tv_nsec = 0; \
415 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 memset(&inode
, 0, sizeof(inode
));
469 err
= ext2fs_read_inode_full(fs
, ino
, (struct ext2_inode
*)&inode
,
472 return translate_error(fs
, ino
, err
);
474 increment_version(&inode
);
475 EXT4_INODE_SET_XTIME(i_ctime
, &now
, &inode
);
477 err
= ext2fs_write_inode_full(fs
, ino
, (struct ext2_inode
*)&inode
,
480 return translate_error(fs
, ino
, err
);
485 static int update_atime(ext2_filsys fs
, ext2_ino_t ino
)
488 struct ext2_inode_large inode
, *pinode
;
489 struct timespec atime
, mtime
, now
;
491 if (!(fs
->flags
& EXT2_FLAG_RW
))
493 memset(&inode
, 0, sizeof(inode
));
494 err
= ext2fs_read_inode_full(fs
, ino
, (struct ext2_inode
*)&inode
,
497 return translate_error(fs
, ino
, err
);
500 EXT4_INODE_GET_XTIME(i_atime
, &atime
, pinode
);
501 EXT4_INODE_GET_XTIME(i_mtime
, &mtime
, pinode
);
504 * If atime is newer than mtime and atime hasn't been updated in thirty
505 * seconds, skip the atime update. Same idea as Linux "relatime".
507 if (atime
.tv_sec
>= mtime
.tv_sec
&& atime
.tv_sec
>= now
.tv_sec
- 30)
509 EXT4_INODE_SET_XTIME(i_atime
, &now
, &inode
);
511 err
= ext2fs_write_inode_full(fs
, ino
, (struct ext2_inode
*)&inode
,
514 return translate_error(fs
, ino
, err
);
519 static int update_mtime(ext2_filsys fs
, ext2_ino_t ino
,
520 struct ext2_inode_large
*pinode
)
523 struct ext2_inode_large inode
;
528 EXT4_INODE_SET_XTIME(i_mtime
, &now
, pinode
);
529 EXT4_INODE_SET_XTIME(i_ctime
, &now
, pinode
);
530 increment_version(pinode
);
534 memset(&inode
, 0, sizeof(inode
));
535 err
= ext2fs_read_inode_full(fs
, ino
, (struct ext2_inode
*)&inode
,
538 return translate_error(fs
, ino
, err
);
541 EXT4_INODE_SET_XTIME(i_mtime
, &now
, &inode
);
542 EXT4_INODE_SET_XTIME(i_ctime
, &now
, &inode
);
543 increment_version(&inode
);
545 err
= ext2fs_write_inode_full(fs
, ino
, (struct ext2_inode
*)&inode
,
548 return translate_error(fs
, ino
, err
);
553 static int ext2_file_type(unsigned int mode
)
555 if (LINUX_S_ISREG(mode
))
556 return EXT2_FT_REG_FILE
;
558 if (LINUX_S_ISDIR(mode
))
561 if (LINUX_S_ISCHR(mode
))
562 return EXT2_FT_CHRDEV
;
564 if (LINUX_S_ISBLK(mode
))
565 return EXT2_FT_BLKDEV
;
567 if (LINUX_S_ISLNK(mode
))
568 return EXT2_FT_SYMLINK
;
570 if (LINUX_S_ISFIFO(mode
))
573 if (LINUX_S_ISSOCK(mode
))
579 static int fs_can_allocate(struct fuse2fs
*ff
, blk64_t num
)
581 ext2_filsys fs
= ff
->fs
;
584 dbg_printf("%s: Asking for %llu; alloc_all=%d total=%llu free=%llu "
585 "rsvd=%llu\n", __func__
, num
, ff
->alloc_all_blocks
,
586 ext2fs_blocks_count(fs
->super
),
587 ext2fs_free_blocks_count(fs
->super
),
588 ext2fs_r_blocks_count(fs
->super
));
589 if (num
> ext2fs_blocks_count(fs
->super
))
592 if (ff
->alloc_all_blocks
)
596 * Different meaning for r_blocks -- libext2fs has bugs where the FS
597 * can get corrupted if it totally runs out of blocks. Avoid this
598 * by refusing to allocate any of the reserve blocks to anybody.
600 reserved
= ext2fs_r_blocks_count(fs
->super
);
602 reserved
= ext2fs_blocks_count(fs
->super
) / 10;
603 return ext2fs_free_blocks_count(fs
->super
) > reserved
+ num
;
606 static int fs_writeable(ext2_filsys fs
)
608 return (fs
->flags
& EXT2_FLAG_RW
) && (fs
->super
->s_error_count
== 0);
611 static int check_inum_access(ext2_filsys fs
, ext2_ino_t ino
, int mask
)
613 struct fuse_context
*ctxt
= fuse_get_context();
614 struct ext2_inode inode
;
618 /* no writing to read-only or broken fs */
619 if ((mask
& W_OK
) && !fs_writeable(fs
))
622 err
= ext2fs_read_inode(fs
, ino
, &inode
);
624 return translate_error(fs
, ino
, err
);
625 perms
= inode
.i_mode
& 0777;
627 dbg_printf("access ino=%d mask=e%s%s%s perms=0%o fuid=%d fgid=%d "
628 "uid=%d gid=%d\n", ino
,
629 (mask
& R_OK
? "r" : ""), (mask
& W_OK
? "w" : ""),
630 (mask
& X_OK
? "x" : ""), perms
, inode
.i_uid
, inode
.i_gid
,
631 ctxt
->uid
, ctxt
->gid
);
633 /* existence check */
639 (inode
.i_flags
& EXT2_IMMUTABLE_FL
))
642 /* Figure out what root's allowed to do */
643 if (ctxt
->uid
== 0) {
644 /* Non-file access always ok */
645 if (!LINUX_S_ISREG(inode
.i_mode
))
648 /* R/W access to a file always ok */
652 /* X access to a file ok if a user/group/other can X */
656 /* Trying to execute a file that's not executable. BZZT! */
660 /* allow owner, if perms match */
661 if (inode
.i_uid
== ctxt
->uid
) {
662 if ((mask
& (perms
>> 6)) == mask
)
667 /* allow group, if perms match */
668 if (inode
.i_gid
== ctxt
->gid
) {
669 if ((mask
& (perms
>> 3)) == mask
)
674 /* otherwise check other */
675 if ((mask
& perms
) == mask
)
680 static void op_destroy(void *p
)
682 struct fuse_context
*ctxt
= fuse_get_context();
683 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
687 if (ff
->magic
!= FUSE2FS_MAGIC
) {
688 translate_error(global_fs
, 0, EXT2_ET_BAD_MAGIC
);
692 dbg_printf("%s: dev=%s\n", __func__
, fs
->device_name
);
693 if (fs
->flags
& EXT2_FLAG_RW
) {
694 fs
->super
->s_state
|= EXT2_VALID_FS
;
695 if (fs
->super
->s_error_count
)
696 fs
->super
->s_state
|= EXT2_ERROR_FS
;
697 ext2fs_mark_super_dirty(fs
);
698 err
= ext2fs_set_gdt_csum(fs
);
700 translate_error(fs
, 0, err
);
702 err
= ext2fs_flush2(fs
, 0);
704 translate_error(fs
, 0, err
);
708 static void *op_init(struct fuse_conn_info
*conn
)
710 struct fuse_context
*ctxt
= fuse_get_context();
711 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
715 if (ff
->magic
!= FUSE2FS_MAGIC
) {
716 translate_error(global_fs
, 0, EXT2_ET_BAD_MAGIC
);
720 dbg_printf("%s: dev=%s\n", __func__
, fs
->device_name
);
721 #ifdef FUSE_CAP_IOCTL_DIR
722 conn
->want
|= FUSE_CAP_IOCTL_DIR
;
724 if (fs
->flags
& EXT2_FLAG_RW
) {
725 fs
->super
->s_mnt_count
++;
726 fs
->super
->s_mtime
= time(NULL
);
727 fs
->super
->s_state
&= ~EXT2_VALID_FS
;
728 ext2fs_mark_super_dirty(fs
);
729 err
= ext2fs_flush2(fs
, 0);
731 translate_error(fs
, 0, err
);
736 static blkcnt_t
blocks_from_inode(ext2_filsys fs
,
737 struct ext2_inode_large
*inode
)
742 if (fs
->super
->s_feature_ro_compat
& EXT4_FEATURE_RO_COMPAT_HUGE_FILE
)
743 b
+= ((long long) inode
->osd2
.linux2
.l_i_blocks_hi
) << 32;
745 if (!(fs
->super
->s_feature_ro_compat
&
746 EXT4_FEATURE_RO_COMPAT_HUGE_FILE
) ||
747 !(inode
->i_flags
& EXT4_HUGE_FILE_FL
))
748 b
*= fs
->blocksize
/ 512;
749 b
*= EXT2FS_CLUSTER_RATIO(fs
);
754 static int stat_inode(ext2_filsys fs
, ext2_ino_t ino
, struct stat
*statbuf
)
756 struct ext2_inode_large inode
;
762 memset(&inode
, 0, sizeof(inode
));
763 err
= ext2fs_read_inode_full(fs
, ino
, (struct ext2_inode
*)&inode
,
766 return translate_error(fs
, ino
, err
);
768 memcpy(&fakedev
, fs
->super
->s_uuid
, sizeof(fakedev
));
769 statbuf
->st_dev
= fakedev
;
770 statbuf
->st_ino
= ino
;
771 statbuf
->st_mode
= inode
.i_mode
;
772 statbuf
->st_nlink
= inode
.i_links_count
;
773 statbuf
->st_uid
= inode
.i_uid
;
774 statbuf
->st_gid
= inode
.i_gid
;
775 statbuf
->st_size
= EXT2_I_SIZE(&inode
);
776 statbuf
->st_blksize
= fs
->blocksize
;
777 statbuf
->st_blocks
= blocks_from_inode(fs
, &inode
);
778 EXT4_INODE_GET_XTIME(i_atime
, &tv
, &inode
);
779 statbuf
->st_atime
= tv
.tv_sec
;
780 EXT4_INODE_GET_XTIME(i_mtime
, &tv
, &inode
);
781 statbuf
->st_mtime
= tv
.tv_sec
;
782 EXT4_INODE_GET_XTIME(i_ctime
, &tv
, &inode
);
783 statbuf
->st_ctime
= tv
.tv_sec
;
784 if (LINUX_S_ISCHR(inode
.i_mode
) ||
785 LINUX_S_ISBLK(inode
.i_mode
)) {
786 if (inode
.i_block
[0])
787 statbuf
->st_rdev
= inode
.i_block
[0];
789 statbuf
->st_rdev
= inode
.i_block
[1];
795 static int op_getattr(const char *path
, struct stat
*statbuf
)
797 struct fuse_context
*ctxt
= fuse_get_context();
798 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
804 FUSE2FS_CHECK_CONTEXT(ff
);
806 dbg_printf("%s: path=%s\n", __func__
, path
);
807 pthread_mutex_lock(&ff
->bfl
);
808 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
810 ret
= translate_error(fs
, 0, err
);
813 ret
= stat_inode(fs
, ino
, statbuf
);
815 pthread_mutex_unlock(&ff
->bfl
);
819 static int op_readlink(const char *path
, char *buf
, size_t len
)
821 struct fuse_context
*ctxt
= fuse_get_context();
822 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
826 struct ext2_inode inode
;
831 FUSE2FS_CHECK_CONTEXT(ff
);
833 dbg_printf("%s: path=%s\n", __func__
, path
);
834 pthread_mutex_lock(&ff
->bfl
);
835 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
836 if (err
|| ino
== 0) {
837 ret
= translate_error(fs
, 0, err
);
841 err
= ext2fs_read_inode(fs
, ino
, &inode
);
843 ret
= translate_error(fs
, ino
, err
);
847 if (!LINUX_S_ISLNK(inode
.i_mode
)) {
853 if (inode
.i_size
< len
)
855 if (ext2fs_inode_data_blocks2(fs
, &inode
) ||
856 (inode
.i_flags
& EXT4_INLINE_DATA_FL
)) {
857 /* big/inline symlink */
859 err
= ext2fs_file_open(fs
, ino
, 0, &file
);
861 ret
= translate_error(fs
, ino
, err
);
865 err
= ext2fs_file_read(file
, buf
, len
, &got
);
866 if (err
|| got
!= len
) {
867 ext2fs_file_close(file
);
868 ret
= translate_error(fs
, ino
, err
);
873 err
= ext2fs_file_close(file
);
877 ret
= translate_error(fs
, ino
, err
);
882 memcpy(buf
, (char *)inode
.i_block
, len
);
885 if (fs_writeable(fs
)) {
886 ret
= update_atime(fs
, ino
);
892 pthread_mutex_unlock(&ff
->bfl
);
896 static int op_mknod(const char *path
, mode_t mode
, dev_t dev
)
898 struct fuse_context
*ctxt
= fuse_get_context();
899 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
901 ext2_ino_t parent
, child
;
902 char *temp_path
= strdup(path
);
906 struct ext2_inode_large inode
;
909 FUSE2FS_CHECK_CONTEXT(ff
);
911 dbg_printf("%s: path=%s mode=0%o dev=0x%x\n", __func__
, path
, mode
,
917 node_name
= strrchr(temp_path
, '/');
926 pthread_mutex_lock(&ff
->bfl
);
927 if (!fs_can_allocate(ff
, 2)) {
932 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, temp_path
,
935 ret
= translate_error(fs
, 0, err
);
939 ret
= check_inum_access(fs
, parent
, W_OK
);
945 if (LINUX_S_ISCHR(mode
))
946 filetype
= EXT2_FT_CHRDEV
;
947 else if (LINUX_S_ISBLK(mode
))
948 filetype
= EXT2_FT_BLKDEV
;
949 else if (LINUX_S_ISFIFO(mode
))
950 filetype
= EXT2_FT_FIFO
;
951 else if (LINUX_S_ISSOCK(mode
))
952 filetype
= EXT2_FT_SOCK
;
958 err
= ext2fs_new_inode(fs
, parent
, mode
, 0, &child
);
960 ret
= translate_error(fs
, 0, err
);
964 dbg_printf("%s: create ino=%d/name=%s in dir=%d\n", __func__
, child
,
966 err
= ext2fs_link(fs
, parent
, node_name
, child
, filetype
);
967 if (err
== EXT2_ET_DIR_NO_SPACE
) {
968 err
= ext2fs_expand_dir(fs
, parent
);
970 ret
= translate_error(fs
, parent
, err
);
974 err
= ext2fs_link(fs
, parent
, node_name
, child
,
978 ret
= translate_error(fs
, parent
, err
);
982 ret
= update_mtime(fs
, parent
, NULL
);
986 memset(&inode
, 0, sizeof(inode
));
990 inode
.i_block
[1] = dev
;
992 inode
.i_block
[0] = dev
;
993 inode
.i_links_count
= 1;
994 inode
.i_extra_isize
= sizeof(struct ext2_inode_large
) -
995 EXT2_GOOD_OLD_INODE_SIZE
;
997 err
= ext2fs_write_new_inode(fs
, child
, (struct ext2_inode
*)&inode
);
999 ret
= translate_error(fs
, child
, err
);
1003 inode
.i_generation
= ff
->next_generation
++;
1005 err
= ext2fs_write_inode_full(fs
, child
, (struct ext2_inode
*)&inode
,
1008 ret
= translate_error(fs
, child
, err
);
1012 ext2fs_inode_alloc_stats2(fs
, child
, 1, 0);
1015 pthread_mutex_unlock(&ff
->bfl
);
1021 static int op_mkdir(const char *path
, mode_t mode
)
1023 struct fuse_context
*ctxt
= fuse_get_context();
1024 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
1026 ext2_ino_t parent
, child
;
1027 char *temp_path
= strdup(path
);
1030 struct ext2_inode_large inode
;
1036 FUSE2FS_CHECK_CONTEXT(ff
);
1038 dbg_printf("%s: path=%s mode=0%o\n", __func__
, path
, mode
);
1043 node_name
= strrchr(temp_path
, '/');
1052 pthread_mutex_lock(&ff
->bfl
);
1053 if (!fs_can_allocate(ff
, 1)) {
1058 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, temp_path
,
1061 ret
= translate_error(fs
, 0, err
);
1065 ret
= check_inum_access(fs
, parent
, W_OK
);
1069 /* Is the parent dir sgid? */
1070 err
= ext2fs_read_inode_full(fs
, parent
, (struct ext2_inode
*)&inode
,
1073 ret
= translate_error(fs
, parent
, err
);
1076 parent_sgid
= inode
.i_mode
& S_ISGID
;
1080 err
= ext2fs_mkdir(fs
, parent
, 0, node_name
);
1081 if (err
== EXT2_ET_DIR_NO_SPACE
) {
1082 err
= ext2fs_expand_dir(fs
, parent
);
1084 ret
= translate_error(fs
, parent
, err
);
1088 err
= ext2fs_mkdir(fs
, parent
, 0, node_name
);
1091 ret
= translate_error(fs
, parent
, err
);
1095 ret
= update_mtime(fs
, parent
, NULL
);
1099 /* Still have to update the uid/gid of the dir */
1100 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, temp_path
,
1103 ret
= translate_error(fs
, 0, err
);
1106 dbg_printf("%s: created ino=%d/path=%s in dir=%d\n", __func__
, child
,
1109 memset(&inode
, 0, sizeof(inode
));
1110 err
= ext2fs_read_inode_full(fs
, child
, (struct ext2_inode
*)&inode
,
1113 ret
= translate_error(fs
, child
, err
);
1117 inode
.i_uid
= ctxt
->uid
;
1118 inode
.i_gid
= ctxt
->gid
;
1119 inode
.i_mode
= LINUX_S_IFDIR
| (mode
& ~(S_ISUID
| fs
->umask
)) |
1121 inode
.i_generation
= ff
->next_generation
++;
1123 err
= ext2fs_write_inode_full(fs
, child
, (struct ext2_inode
*)&inode
,
1126 ret
= translate_error(fs
, child
, err
);
1130 /* Rewrite the directory block checksum, having set i_generation */
1131 if ((inode
.i_flags
& EXT4_INLINE_DATA_FL
) ||
1132 !EXT2_HAS_RO_COMPAT_FEATURE(fs
->super
,
1133 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM
))
1135 err
= ext2fs_new_dir_block(fs
, child
, parent
, &block
);
1137 ret
= translate_error(fs
, child
, err
);
1140 err
= ext2fs_bmap2(fs
, child
, (struct ext2_inode
*)&inode
, NULL
, 0, 0,
1143 ret
= translate_error(fs
, child
, err
);
1146 err
= ext2fs_write_dir_block4(fs
, blk
, block
, 0, child
);
1148 ret
= translate_error(fs
, child
, err
);
1153 ext2fs_free_mem(&block
);
1155 pthread_mutex_unlock(&ff
->bfl
);
1161 static int unlink_file_by_name(ext2_filsys fs
, const char *path
)
1165 char *filename
= strdup(path
);
1169 base_name
= strrchr(filename
, '/');
1171 *base_name
++ = '\0';
1172 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, filename
,
1176 return translate_error(fs
, 0, err
);
1179 dir
= EXT2_ROOT_INO
;
1180 base_name
= filename
;
1183 ret
= check_inum_access(fs
, dir
, W_OK
);
1189 dbg_printf("%s: unlinking name=%s from dir=%d\n", __func__
,
1191 err
= ext2fs_unlink(fs
, dir
, base_name
, 0, 0);
1194 return translate_error(fs
, dir
, err
);
1196 return update_mtime(fs
, dir
, NULL
);
1199 static int remove_inode(struct fuse2fs
*ff
, ext2_ino_t ino
)
1201 ext2_filsys fs
= ff
->fs
;
1203 struct ext2_inode_large inode
;
1206 memset(&inode
, 0, sizeof(inode
));
1207 err
= ext2fs_read_inode_full(fs
, ino
, (struct ext2_inode
*)&inode
,
1210 ret
= translate_error(fs
, ino
, err
);
1213 dbg_printf("%s: put ino=%d links=%d\n", __func__
, ino
,
1214 inode
.i_links_count
);
1216 switch (inode
.i_links_count
) {
1218 return 0; /* XXX: already done? */
1220 inode
.i_links_count
--;
1221 inode
.i_dtime
= fs
->now
? fs
->now
: time(0);
1224 inode
.i_links_count
--;
1227 ret
= update_ctime(fs
, ino
, &inode
);
1231 if (inode
.i_links_count
)
1234 /* Nobody holds this file; free its blocks! */
1235 err
= ext2fs_free_ext_attr(fs
, ino
, &inode
);
1239 if (ext2fs_inode_has_valid_blocks2(fs
, (struct ext2_inode
*)&inode
)) {
1240 err
= ext2fs_punch(fs
, ino
, (struct ext2_inode
*)&inode
, NULL
,
1243 ret
= translate_error(fs
, ino
, err
);
1248 ext2fs_inode_alloc_stats2(fs
, ino
, -1,
1249 LINUX_S_ISDIR(inode
.i_mode
));
1252 err
= ext2fs_write_inode_full(fs
, ino
, (struct ext2_inode
*)&inode
,
1255 ret
= translate_error(fs
, ino
, err
);
1262 static int __op_unlink(struct fuse2fs
*ff
, const char *path
)
1264 ext2_filsys fs
= ff
->fs
;
1269 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
1271 ret
= translate_error(fs
, 0, err
);
1275 ret
= unlink_file_by_name(fs
, path
);
1279 ret
= remove_inode(ff
, ino
);
1286 static int op_unlink(const char *path
)
1288 struct fuse_context
*ctxt
= fuse_get_context();
1289 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
1292 FUSE2FS_CHECK_CONTEXT(ff
);
1293 pthread_mutex_lock(&ff
->bfl
);
1294 ret
= __op_unlink(ff
, path
);
1295 pthread_mutex_unlock(&ff
->bfl
);
1304 static int rmdir_proc(ext2_ino_t dir
EXT2FS_ATTR((unused
)),
1305 int entry
EXT2FS_ATTR((unused
)),
1306 struct ext2_dir_entry
*dirent
,
1307 int offset
EXT2FS_ATTR((unused
)),
1308 int blocksize
EXT2FS_ATTR((unused
)),
1309 char *buf
EXT2FS_ATTR((unused
)),
1312 struct rd_struct
*rds
= (struct rd_struct
*) private;
1314 if (dirent
->inode
== 0)
1316 if (((dirent
->name_len
& 0xFF) == 1) && (dirent
->name
[0] == '.'))
1318 if (((dirent
->name_len
& 0xFF) == 2) && (dirent
->name
[0] == '.') &&
1319 (dirent
->name
[1] == '.')) {
1320 rds
->parent
= dirent
->inode
;
1327 static int __op_rmdir(struct fuse2fs
*ff
, const char *path
)
1329 ext2_filsys fs
= ff
->fs
;
1332 struct ext2_inode_large inode
;
1333 struct rd_struct rds
;
1336 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &child
);
1338 ret
= translate_error(fs
, 0, err
);
1341 dbg_printf("%s: rmdir path=%s ino=%d\n", __func__
, path
, child
);
1346 err
= ext2fs_dir_iterate2(fs
, child
, 0, 0, rmdir_proc
, &rds
);
1348 ret
= translate_error(fs
, child
, err
);
1352 if (rds
.empty
== 0) {
1357 ret
= unlink_file_by_name(fs
, path
);
1360 /* Directories have to be "removed" twice. */
1361 ret
= remove_inode(ff
, child
);
1364 ret
= remove_inode(ff
, child
);
1369 dbg_printf("%s: decr dir=%d link count\n", __func__
,
1371 err
= ext2fs_read_inode_full(fs
, rds
.parent
,
1372 (struct ext2_inode
*)&inode
,
1375 ret
= translate_error(fs
, rds
.parent
, err
);
1378 if (inode
.i_links_count
> 1)
1379 inode
.i_links_count
--;
1380 ret
= update_mtime(fs
, rds
.parent
, &inode
);
1383 err
= ext2fs_write_inode_full(fs
, rds
.parent
,
1384 (struct ext2_inode
*)&inode
,
1387 ret
= translate_error(fs
, rds
.parent
, err
);
1396 static int op_rmdir(const char *path
)
1398 struct fuse_context
*ctxt
= fuse_get_context();
1399 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
1402 FUSE2FS_CHECK_CONTEXT(ff
);
1403 pthread_mutex_lock(&ff
->bfl
);
1404 ret
= __op_rmdir(ff
, path
);
1405 pthread_mutex_unlock(&ff
->bfl
);
1409 static int op_symlink(const char *src
, const char *dest
)
1411 struct fuse_context
*ctxt
= fuse_get_context();
1412 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
1414 ext2_ino_t parent
, child
;
1415 char *temp_path
= strdup(dest
);
1418 struct ext2_inode_large inode
;
1421 FUSE2FS_CHECK_CONTEXT(ff
);
1423 dbg_printf("%s: symlink %s to %s\n", __func__
, src
, dest
);
1428 node_name
= strrchr(temp_path
, '/');
1437 pthread_mutex_lock(&ff
->bfl
);
1438 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, temp_path
,
1442 ret
= translate_error(fs
, 0, err
);
1446 ret
= check_inum_access(fs
, parent
, W_OK
);
1451 /* Create symlink */
1452 err
= ext2fs_symlink(fs
, parent
, 0, node_name
, (char *)src
);
1453 if (err
== EXT2_ET_DIR_NO_SPACE
) {
1454 err
= ext2fs_expand_dir(fs
, parent
);
1456 ret
= translate_error(fs
, parent
, err
);
1460 err
= ext2fs_symlink(fs
, parent
, 0, node_name
, (char *)src
);
1463 ret
= translate_error(fs
, parent
, err
);
1467 /* Update parent dir's mtime */
1468 ret
= update_mtime(fs
, parent
, NULL
);
1472 /* Still have to update the uid/gid of the symlink */
1473 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, temp_path
,
1476 ret
= translate_error(fs
, 0, err
);
1479 dbg_printf("%s: symlinking ino=%d/name=%s to dir=%d\n", __func__
,
1480 child
, node_name
, parent
);
1482 memset(&inode
, 0, sizeof(inode
));
1483 err
= ext2fs_read_inode_full(fs
, child
, (struct ext2_inode
*)&inode
,
1486 ret
= translate_error(fs
, child
, err
);
1490 inode
.i_uid
= ctxt
->uid
;
1491 inode
.i_gid
= ctxt
->gid
;
1492 inode
.i_generation
= ff
->next_generation
++;
1494 err
= ext2fs_write_inode_full(fs
, child
, (struct ext2_inode
*)&inode
,
1497 ret
= translate_error(fs
, child
, err
);
1501 pthread_mutex_unlock(&ff
->bfl
);
1507 struct update_dotdot
{
1508 ext2_ino_t new_dotdot
;
1511 static int update_dotdot_helper(ext2_ino_t dir
, int entry
,
1512 struct ext2_dir_entry
*dirent
, int offset
,
1513 int blocksize
, char *buf
, void *priv_data
)
1515 struct update_dotdot
*ud
= priv_data
;
1517 if (ext2fs_dirent_name_len(dirent
) == 2 &&
1518 dirent
->name
[0] == '.' && dirent
->name
[1] == '.') {
1519 dirent
->inode
= ud
->new_dotdot
;
1520 return DIRENT_CHANGED
| DIRENT_ABORT
;
1526 static int op_rename(const char *from
, const char *to
)
1528 struct fuse_context
*ctxt
= fuse_get_context();
1529 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
1532 ext2_ino_t from_ino
, to_ino
, to_dir_ino
, from_dir_ino
;
1533 char *temp_to
= NULL
, *temp_from
= NULL
;
1535 struct ext2_inode inode
;
1536 struct update_dotdot ud
;
1539 FUSE2FS_CHECK_CONTEXT(ff
);
1541 dbg_printf("%s: renaming %s to %s\n", __func__
, from
, to
);
1542 pthread_mutex_lock(&ff
->bfl
);
1543 if (!fs_can_allocate(ff
, 5)) {
1548 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, from
, &from_ino
);
1549 if (err
|| from_ino
== 0) {
1550 ret
= translate_error(fs
, 0, err
);
1554 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, to
, &to_ino
);
1555 if (err
&& err
!= EXT2_ET_FILE_NOT_FOUND
) {
1556 ret
= translate_error(fs
, 0, err
);
1560 if (err
== EXT2_ET_FILE_NOT_FOUND
)
1563 /* Already the same file? */
1564 if (to_ino
!= 0 && to_ino
== from_ino
) {
1569 temp_to
= strdup(to
);
1575 temp_from
= strdup(from
);
1581 /* Find parent dir of the source and check write access */
1582 cp
= strrchr(temp_from
, '/');
1590 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, temp_from
,
1594 ret
= translate_error(fs
, 0, err
);
1597 if (from_dir_ino
== 0) {
1602 ret
= check_inum_access(fs
, from_dir_ino
, W_OK
);
1606 /* Find parent dir of the destination and check write access */
1607 cp
= strrchr(temp_to
, '/');
1615 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, temp_to
,
1619 ret
= translate_error(fs
, 0, err
);
1622 if (to_dir_ino
== 0) {
1627 ret
= check_inum_access(fs
, to_dir_ino
, W_OK
);
1631 /* If the target exists, unlink it first */
1633 err
= ext2fs_read_inode(fs
, to_ino
, &inode
);
1635 ret
= translate_error(fs
, to_ino
, err
);
1639 dbg_printf("%s: unlinking %s ino=%d\n", __func__
,
1640 LINUX_S_ISDIR(inode
.i_mode
) ? "dir" : "file",
1642 if (LINUX_S_ISDIR(inode
.i_mode
))
1643 ret
= __op_rmdir(ff
, to
);
1645 ret
= __op_unlink(ff
, to
);
1650 /* Get ready to do the move */
1651 err
= ext2fs_read_inode(fs
, from_ino
, &inode
);
1653 ret
= translate_error(fs
, from_ino
, err
);
1657 /* Link in the new file */
1658 dbg_printf("%s: linking ino=%d/path=%s to dir=%d\n", __func__
,
1659 from_ino
, cp
+ 1, to_dir_ino
);
1660 err
= ext2fs_link(fs
, to_dir_ino
, cp
+ 1, from_ino
,
1661 ext2_file_type(inode
.i_mode
));
1662 if (err
== EXT2_ET_DIR_NO_SPACE
) {
1663 err
= ext2fs_expand_dir(fs
, to_dir_ino
);
1665 ret
= translate_error(fs
, to_dir_ino
, err
);
1669 err
= ext2fs_link(fs
, to_dir_ino
, cp
+ 1, from_ino
,
1670 ext2_file_type(inode
.i_mode
));
1673 ret
= translate_error(fs
, to_dir_ino
, err
);
1677 /* Update '..' pointer if dir */
1678 err
= ext2fs_read_inode(fs
, from_ino
, &inode
);
1680 ret
= translate_error(fs
, from_ino
, err
);
1684 if (LINUX_S_ISDIR(inode
.i_mode
)) {
1685 ud
.new_dotdot
= to_dir_ino
;
1686 dbg_printf("%s: updating .. entry for dir=%d\n", __func__
,
1688 err
= ext2fs_dir_iterate2(fs
, from_ino
, 0, NULL
,
1689 update_dotdot_helper
, &ud
);
1691 ret
= translate_error(fs
, from_ino
, err
);
1695 /* Decrease from_dir_ino's links_count */
1696 dbg_printf("%s: moving linkcount from dir=%d to dir=%d\n",
1697 __func__
, from_dir_ino
, to_dir_ino
);
1698 err
= ext2fs_read_inode(fs
, from_dir_ino
, &inode
);
1700 ret
= translate_error(fs
, from_dir_ino
, err
);
1703 inode
.i_links_count
--;
1704 err
= ext2fs_write_inode(fs
, from_dir_ino
, &inode
);
1706 ret
= translate_error(fs
, from_dir_ino
, err
);
1710 /* Increase to_dir_ino's links_count */
1711 err
= ext2fs_read_inode(fs
, to_dir_ino
, &inode
);
1713 ret
= translate_error(fs
, to_dir_ino
, err
);
1716 inode
.i_links_count
++;
1717 err
= ext2fs_write_inode(fs
, to_dir_ino
, &inode
);
1719 ret
= translate_error(fs
, to_dir_ino
, err
);
1724 /* Update timestamps */
1725 ret
= update_ctime(fs
, from_ino
, NULL
);
1729 ret
= update_mtime(fs
, to_dir_ino
, NULL
);
1733 /* Remove the old file */
1734 ret
= unlink_file_by_name(fs
, from
);
1738 /* Flush the whole mess out */
1739 err
= ext2fs_flush2(fs
, 0);
1741 ret
= translate_error(fs
, 0, err
);
1747 pthread_mutex_unlock(&ff
->bfl
);
1751 static int op_link(const char *src
, const char *dest
)
1753 struct fuse_context
*ctxt
= fuse_get_context();
1754 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
1756 char *temp_path
= strdup(dest
);
1759 ext2_ino_t parent
, ino
;
1760 struct ext2_inode_large inode
;
1763 FUSE2FS_CHECK_CONTEXT(ff
);
1765 dbg_printf("%s: src=%s dest=%s\n", __func__
, src
, dest
);
1770 node_name
= strrchr(temp_path
, '/');
1779 pthread_mutex_lock(&ff
->bfl
);
1780 if (!fs_can_allocate(ff
, 2)) {
1785 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, temp_path
,
1793 ret
= check_inum_access(fs
, parent
, W_OK
);
1798 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, src
, &ino
);
1799 if (err
|| ino
== 0) {
1800 ret
= translate_error(fs
, 0, err
);
1804 memset(&inode
, 0, sizeof(inode
));
1805 err
= ext2fs_read_inode_full(fs
, ino
, (struct ext2_inode
*)&inode
,
1808 ret
= translate_error(fs
, ino
, err
);
1812 inode
.i_links_count
++;
1813 ret
= update_ctime(fs
, ino
, &inode
);
1817 err
= ext2fs_write_inode_full(fs
, ino
, (struct ext2_inode
*)&inode
,
1820 ret
= translate_error(fs
, ino
, err
);
1824 dbg_printf("%s: linking ino=%d/name=%s to dir=%d\n", __func__
, ino
,
1826 err
= ext2fs_link(fs
, parent
, node_name
, ino
,
1827 ext2_file_type(inode
.i_mode
));
1828 if (err
== EXT2_ET_DIR_NO_SPACE
) {
1829 err
= ext2fs_expand_dir(fs
, parent
);
1831 ret
= translate_error(fs
, parent
, err
);
1835 err
= ext2fs_link(fs
, parent
, node_name
, ino
,
1836 ext2_file_type(inode
.i_mode
));
1839 ret
= translate_error(fs
, parent
, err
);
1843 ret
= update_mtime(fs
, parent
, NULL
);
1848 pthread_mutex_unlock(&ff
->bfl
);
1854 static int op_chmod(const char *path
, mode_t mode
)
1856 struct fuse_context
*ctxt
= fuse_get_context();
1857 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
1861 struct ext2_inode_large inode
;
1864 FUSE2FS_CHECK_CONTEXT(ff
);
1866 pthread_mutex_lock(&ff
->bfl
);
1867 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
1869 ret
= translate_error(fs
, 0, err
);
1872 dbg_printf("%s: path=%s mode=0%o ino=%d\n", __func__
, path
, mode
, ino
);
1874 memset(&inode
, 0, sizeof(inode
));
1875 err
= ext2fs_read_inode_full(fs
, ino
, (struct ext2_inode
*)&inode
,
1878 ret
= translate_error(fs
, ino
, err
);
1882 if (ctxt
->uid
!= 0 && ctxt
->uid
!= inode
.i_uid
) {
1888 * XXX: We should really check that the inode gid is not in /any/
1889 * of the user's groups, but FUSE only tells us about the primary
1892 if (ctxt
->uid
!= 0 && ctxt
->gid
!= inode
.i_gid
)
1895 inode
.i_mode
&= ~0xFFF;
1896 inode
.i_mode
|= mode
& 0xFFF;
1897 ret
= update_ctime(fs
, ino
, &inode
);
1901 err
= ext2fs_write_inode_full(fs
, ino
, (struct ext2_inode
*)&inode
,
1904 ret
= translate_error(fs
, ino
, err
);
1909 pthread_mutex_unlock(&ff
->bfl
);
1913 static int op_chown(const char *path
, uid_t owner
, gid_t group
)
1915 struct fuse_context
*ctxt
= fuse_get_context();
1916 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
1920 struct ext2_inode_large inode
;
1923 FUSE2FS_CHECK_CONTEXT(ff
);
1925 pthread_mutex_lock(&ff
->bfl
);
1926 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
1928 ret
= translate_error(fs
, 0, err
);
1931 dbg_printf("%s: path=%s owner=%d group=%d ino=%d\n", __func__
,
1932 path
, owner
, group
, ino
);
1934 memset(&inode
, 0, sizeof(inode
));
1935 err
= ext2fs_read_inode_full(fs
, ino
, (struct ext2_inode
*)&inode
,
1938 ret
= translate_error(fs
, ino
, err
);
1942 /* FUSE seems to feed us ~0 to mean "don't change" */
1944 /* Only root gets to change UID. */
1945 if (ctxt
->uid
!= 0 &&
1946 !(inode
.i_uid
== ctxt
->uid
&& owner
== ctxt
->uid
)) {
1950 inode
.i_uid
= owner
;
1954 /* Only root or the owner get to change GID. */
1955 if (ctxt
->uid
!= 0 && inode
.i_uid
!= ctxt
->uid
) {
1960 /* XXX: We /should/ check group membership but FUSE */
1961 inode
.i_gid
= group
;
1964 ret
= update_ctime(fs
, ino
, &inode
);
1968 err
= ext2fs_write_inode_full(fs
, ino
, (struct ext2_inode
*)&inode
,
1971 ret
= translate_error(fs
, ino
, err
);
1976 pthread_mutex_unlock(&ff
->bfl
);
1980 static int op_truncate(const char *path
, off_t len
)
1982 struct fuse_context
*ctxt
= fuse_get_context();
1983 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
1990 FUSE2FS_CHECK_CONTEXT(ff
);
1992 pthread_mutex_lock(&ff
->bfl
);
1993 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
1994 if (err
|| ino
== 0) {
1995 ret
= translate_error(fs
, 0, err
);
1998 dbg_printf("%s: ino=%d len=%jd\n", __func__
, ino
, len
);
2000 ret
= check_inum_access(fs
, ino
, W_OK
);
2004 err
= ext2fs_file_open(fs
, ino
, EXT2_FILE_WRITE
, &file
);
2006 ret
= translate_error(fs
, ino
, err
);
2010 err
= ext2fs_file_set_size2(file
, len
);
2012 ret
= translate_error(fs
, ino
, err
);
2017 err
= ext2fs_file_close(file
);
2021 ret
= translate_error(fs
, ino
, err
);
2025 ret
= update_mtime(fs
, ino
, NULL
);
2028 pthread_mutex_unlock(&ff
->bfl
);
2033 static void detect_linux_executable_open(int kernel_flags
, int *access_check
,
2034 int *e2fs_open_flags
)
2037 * On Linux, execve will bleed __FMODE_EXEC into the file mode flags,
2038 * and FUSE is more than happy to let that slip through.
2040 if (kernel_flags
& 0x20) {
2041 *access_check
= X_OK
;
2042 *e2fs_open_flags
&= ~EXT2_FILE_WRITE
;
2046 static void detect_linux_executable_open(int kernel_flags
, int *access_check
,
2047 int *e2fs_open_flags
)
2051 #endif /* __linux__ */
2053 static int __op_open(struct fuse2fs
*ff
, const char *path
,
2054 struct fuse_file_info
*fp
)
2056 ext2_filsys fs
= ff
->fs
;
2058 struct fuse2fs_file_handle
*file
;
2059 int check
= 0, ret
= 0;
2061 dbg_printf("%s: path=%s\n", __func__
, path
);
2062 err
= ext2fs_get_mem(sizeof(*file
), &file
);
2064 return translate_error(fs
, 0, err
);
2065 file
->magic
= FUSE2FS_FILE_MAGIC
;
2067 file
->open_flags
= 0;
2068 switch (fp
->flags
& O_ACCMODE
) {
2074 file
->open_flags
|= EXT2_FILE_WRITE
;
2077 check
= R_OK
| W_OK
;
2078 file
->open_flags
|= EXT2_FILE_WRITE
;
2082 detect_linux_executable_open(fp
->flags
, &check
, &file
->open_flags
);
2084 if (fp
->flags
& O_CREAT
)
2085 file
->open_flags
|= EXT2_FILE_CREATE
;
2087 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &file
->ino
);
2088 if (err
|| file
->ino
== 0) {
2089 ret
= translate_error(fs
, 0, err
);
2092 dbg_printf("%s: ino=%d\n", __func__
, file
->ino
);
2094 ret
= check_inum_access(fs
, file
->ino
, check
);
2097 * In a regular (Linux) fs driver, the kernel will open
2098 * binaries for reading if the user has --x privileges (i.e.
2099 * execute without read). Since the kernel doesn't have any
2100 * way to tell us if it's opening a file via execve, we'll
2101 * just assume that allowing access is ok if asking for ro mode
2102 * fails but asking for x mode succeeds. Of course we can
2103 * also employ undocumented hacks (see above).
2105 if (check
== R_OK
) {
2106 ret
= check_inum_access(fs
, file
->ino
, X_OK
);
2112 fp
->fh
= (uint64_t)file
;
2116 ext2fs_free_mem(&file
);
2120 static int op_open(const char *path
, struct fuse_file_info
*fp
)
2122 struct fuse_context
*ctxt
= fuse_get_context();
2123 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2126 FUSE2FS_CHECK_CONTEXT(ff
);
2127 pthread_mutex_lock(&ff
->bfl
);
2128 ret
= __op_open(ff
, path
, fp
);
2129 pthread_mutex_unlock(&ff
->bfl
);
2133 static int op_read(const char *path
, char *buf
, size_t len
, off_t offset
,
2134 struct fuse_file_info
*fp
)
2136 struct fuse_context
*ctxt
= fuse_get_context();
2137 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2138 struct fuse2fs_file_handle
*fh
= (struct fuse2fs_file_handle
*)fp
->fh
;
2142 unsigned int got
= 0;
2145 FUSE2FS_CHECK_CONTEXT(ff
);
2147 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
2148 dbg_printf("%s: ino=%d off=%jd len=%jd\n", __func__
, fh
->ino
, offset
,
2150 pthread_mutex_lock(&ff
->bfl
);
2151 err
= ext2fs_file_open(fs
, fh
->ino
, fh
->open_flags
, &efp
);
2153 ret
= translate_error(fs
, fh
->ino
, err
);
2157 err
= ext2fs_file_llseek(efp
, offset
, SEEK_SET
, NULL
);
2159 ret
= translate_error(fs
, fh
->ino
, err
);
2163 err
= ext2fs_file_read(efp
, buf
, len
, &got
);
2165 ret
= translate_error(fs
, fh
->ino
, err
);
2170 err
= ext2fs_file_close(efp
);
2174 ret
= translate_error(fs
, fh
->ino
, err
);
2178 if (fs_writeable(fs
)) {
2179 ret
= update_atime(fs
, fh
->ino
);
2184 pthread_mutex_unlock(&ff
->bfl
);
2185 return got
? got
: ret
;
2188 static int op_write(const char *path
, const char *buf
, size_t len
, off_t offset
,
2189 struct fuse_file_info
*fp
)
2191 struct fuse_context
*ctxt
= fuse_get_context();
2192 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2193 struct fuse2fs_file_handle
*fh
= (struct fuse2fs_file_handle
*)fp
->fh
;
2197 unsigned int got
= 0;
2200 FUSE2FS_CHECK_CONTEXT(ff
);
2202 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
2203 dbg_printf("%s: ino=%d off=%jd len=%jd\n", __func__
, fh
->ino
, offset
,
2205 pthread_mutex_lock(&ff
->bfl
);
2206 if (!fs_writeable(fs
)) {
2211 if (!fs_can_allocate(ff
, len
/ fs
->blocksize
)) {
2216 err
= ext2fs_file_open(fs
, fh
->ino
, fh
->open_flags
, &efp
);
2218 ret
= translate_error(fs
, fh
->ino
, err
);
2222 err
= ext2fs_file_llseek(efp
, offset
, SEEK_SET
, NULL
);
2224 ret
= translate_error(fs
, fh
->ino
, err
);
2228 err
= ext2fs_file_write(efp
, buf
, len
, &got
);
2230 ret
= translate_error(fs
, fh
->ino
, err
);
2234 err
= ext2fs_file_flush(efp
);
2237 ret
= translate_error(fs
, fh
->ino
, err
);
2242 err
= ext2fs_file_close(efp
);
2246 ret
= translate_error(fs
, fh
->ino
, err
);
2250 ret
= update_mtime(fs
, fh
->ino
, NULL
);
2255 pthread_mutex_unlock(&ff
->bfl
);
2256 return got
? got
: ret
;
2259 static int op_release(const char *path
, struct fuse_file_info
*fp
)
2261 struct fuse_context
*ctxt
= fuse_get_context();
2262 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2263 struct fuse2fs_file_handle
*fh
= (struct fuse2fs_file_handle
*)fp
->fh
;
2268 FUSE2FS_CHECK_CONTEXT(ff
);
2270 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
2271 dbg_printf("%s: ino=%d\n", __func__
, fh
->ino
);
2272 pthread_mutex_lock(&ff
->bfl
);
2273 if (fs_writeable(fs
) && fh
->open_flags
& EXT2_FILE_WRITE
) {
2274 err
= ext2fs_flush2(fs
, EXT2_FLAG_FLUSH_NO_SYNC
);
2276 ret
= translate_error(fs
, fh
->ino
, err
);
2279 pthread_mutex_unlock(&ff
->bfl
);
2281 ext2fs_free_mem(&fh
);
2286 static int op_fsync(const char *path
, int datasync
, struct fuse_file_info
*fp
)
2288 struct fuse_context
*ctxt
= fuse_get_context();
2289 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2290 struct fuse2fs_file_handle
*fh
= (struct fuse2fs_file_handle
*)fp
->fh
;
2295 FUSE2FS_CHECK_CONTEXT(ff
);
2297 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
2298 dbg_printf("%s: ino=%d\n", __func__
, fh
->ino
);
2299 /* For now, flush everything, even if it's slow */
2300 pthread_mutex_lock(&ff
->bfl
);
2301 if (fs_writeable(fs
) && fh
->open_flags
& EXT2_FILE_WRITE
) {
2302 err
= ext2fs_flush2(fs
, 0);
2304 ret
= translate_error(fs
, fh
->ino
, err
);
2306 pthread_mutex_unlock(&ff
->bfl
);
2311 static int op_statfs(const char *path
, struct statvfs
*buf
)
2313 struct fuse_context
*ctxt
= fuse_get_context();
2314 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2317 blk64_t overhead
, reserved
, free
;
2319 FUSE2FS_CHECK_CONTEXT(ff
);
2321 dbg_printf("%s: path=%s\n", __func__
, path
);
2322 buf
->f_bsize
= fs
->blocksize
;
2328 overhead
= fs
->desc_blocks
+
2329 fs
->group_desc_count
*
2330 (fs
->inode_blocks_per_group
+ 2);
2331 reserved
= ext2fs_r_blocks_count(fs
->super
);
2333 reserved
= ext2fs_blocks_count(fs
->super
) / 10;
2334 free
= ext2fs_free_blocks_count(fs
->super
);
2336 buf
->f_blocks
= ext2fs_blocks_count(fs
->super
) - overhead
;
2337 buf
->f_bfree
= free
;
2338 if (free
< reserved
)
2341 buf
->f_bavail
= free
- reserved
;
2342 buf
->f_files
= fs
->super
->s_inodes_count
;
2343 buf
->f_ffree
= fs
->super
->s_free_inodes_count
;
2344 buf
->f_favail
= fs
->super
->s_free_inodes_count
;
2345 f
= (uint64_t *)fs
->super
->s_uuid
;
2351 if (fs
->flags
& EXT2_FLAG_RW
)
2352 buf
->f_flag
|= ST_RDONLY
;
2353 buf
->f_namemax
= EXT2_NAME_LEN
;
2358 typedef errcode_t (*xattr_xlate_get
)(void **cooked_buf
, size_t *cooked_sz
,
2359 const void *raw_buf
, size_t raw_sz
);
2360 typedef errcode_t (*xattr_xlate_set
)(const void *cooked_buf
, size_t cooked_sz
,
2361 void **raw_buf
, size_t *raw_sz
);
2362 struct xattr_translate
{
2364 xattr_xlate_get get
;
2365 xattr_xlate_set set
;
2368 #define XATTR_TRANSLATOR(p, g, s) \
2370 .get = (xattr_xlate_get)(g), \
2371 .set = (xattr_xlate_set)(s)}
2373 static struct xattr_translate xattr_translators
[] = {
2374 #ifdef TRANSLATE_LINUX_ACLS
2375 XATTR_TRANSLATOR(ACL_EA_ACCESS
, ext4_to_fuse_acl
, fuse_to_ext4_acl
),
2376 XATTR_TRANSLATOR(ACL_EA_DEFAULT
, ext4_to_fuse_acl
, fuse_to_ext4_acl
),
2378 XATTR_TRANSLATOR(NULL
, NULL
, NULL
),
2380 #undef XATTR_TRANSLATOR
2382 static int op_getxattr(const char *path
, const char *key
, char *value
,
2385 struct fuse_context
*ctxt
= fuse_get_context();
2386 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2388 struct ext2_xattr_handle
*h
;
2389 struct xattr_translate
*xt
;
2396 FUSE2FS_CHECK_CONTEXT(ff
);
2398 pthread_mutex_lock(&ff
->bfl
);
2399 if (!EXT2_HAS_COMPAT_FEATURE(fs
->super
,
2400 EXT2_FEATURE_COMPAT_EXT_ATTR
)) {
2405 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
2406 if (err
|| ino
== 0) {
2407 ret
= translate_error(fs
, 0, err
);
2410 dbg_printf("%s: ino=%d\n", __func__
, ino
);
2412 ret
= check_inum_access(fs
, ino
, R_OK
);
2416 err
= ext2fs_xattrs_open(fs
, ino
, &h
);
2418 ret
= translate_error(fs
, ino
, err
);
2422 err
= ext2fs_xattrs_read(h
);
2424 ret
= translate_error(fs
, ino
, err
);
2428 err
= ext2fs_xattr_get(h
, key
, &ptr
, &plen
);
2430 ret
= translate_error(fs
, ino
, err
);
2434 for (xt
= xattr_translators
; xt
->prefix
!= NULL
; xt
++) {
2435 if (strncmp(key
, xt
->prefix
, strlen(xt
->prefix
)) == 0) {
2436 err
= xt
->get(&cptr
, &clen
, ptr
, plen
);
2439 ext2fs_free_mem(&ptr
);
2447 } else if (len
< plen
) {
2450 memcpy(value
, ptr
, plen
);
2455 ext2fs_free_mem(&ptr
);
2457 err
= ext2fs_xattrs_close(&h
);
2459 ret
= translate_error(fs
, ino
, err
);
2461 pthread_mutex_unlock(&ff
->bfl
);
2466 static int count_buffer_space(char *name
, char *value
, size_t value_len
,
2469 unsigned int *x
= data
;
2471 *x
= *x
+ strlen(name
) + 1;
2475 static int copy_names(char *name
, char *value
, size_t value_len
, void *data
)
2479 strncpy(*b
, name
, strlen(name
));
2480 *b
= *b
+ strlen(name
) + 1;
2485 static int op_listxattr(const char *path
, char *names
, size_t len
)
2487 struct fuse_context
*ctxt
= fuse_get_context();
2488 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2490 struct ext2_xattr_handle
*h
;
2496 FUSE2FS_CHECK_CONTEXT(ff
);
2498 pthread_mutex_lock(&ff
->bfl
);
2499 if (!EXT2_HAS_COMPAT_FEATURE(fs
->super
,
2500 EXT2_FEATURE_COMPAT_EXT_ATTR
)) {
2505 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
2506 if (err
|| ino
== 0) {
2507 ret
= translate_error(fs
, ino
, err
);
2510 dbg_printf("%s: ino=%d\n", __func__
, ino
);
2512 ret
= check_inum_access(fs
, ino
, R_OK
);
2516 err
= ext2fs_xattrs_open(fs
, ino
, &h
);
2518 ret
= translate_error(fs
, ino
, err
);
2522 err
= ext2fs_xattrs_read(h
);
2524 ret
= translate_error(fs
, ino
, err
);
2528 /* Count buffer space needed for names */
2530 err
= ext2fs_xattrs_iterate(h
, count_buffer_space
, &bufsz
);
2532 ret
= translate_error(fs
, ino
, err
);
2539 } else if (len
< bufsz
) {
2544 /* Copy names out */
2545 memset(names
, 0, len
);
2546 err
= ext2fs_xattrs_iterate(h
, copy_names
, &names
);
2548 ret
= translate_error(fs
, ino
, err
);
2553 err
= ext2fs_xattrs_close(&h
);
2555 ret
= translate_error(fs
, ino
, err
);
2557 pthread_mutex_unlock(&ff
->bfl
);
2562 static int op_setxattr(const char *path
, const char *key
, const char *value
,
2563 size_t len
, int flags
)
2565 struct fuse_context
*ctxt
= fuse_get_context();
2566 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2568 struct ext2_xattr_handle
*h
;
2569 struct xattr_translate
*xt
;
2576 FUSE2FS_CHECK_CONTEXT(ff
);
2578 pthread_mutex_lock(&ff
->bfl
);
2579 if (!EXT2_HAS_COMPAT_FEATURE(fs
->super
,
2580 EXT2_FEATURE_COMPAT_EXT_ATTR
)) {
2585 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
2586 if (err
|| ino
== 0) {
2587 ret
= translate_error(fs
, 0, err
);
2590 dbg_printf("%s: ino=%d\n", __func__
, ino
);
2592 ret
= check_inum_access(fs
, ino
, W_OK
);
2593 if (ret
== -EACCES
) {
2599 err
= ext2fs_xattrs_open(fs
, ino
, &h
);
2601 ret
= translate_error(fs
, ino
, err
);
2605 err
= ext2fs_xattrs_read(h
);
2607 ret
= translate_error(fs
, ino
, err
);
2611 cvalue
= (void *)value
;
2613 for (xt
= xattr_translators
; xt
->prefix
!= NULL
; xt
++) {
2614 if (strncmp(key
, xt
->prefix
, strlen(xt
->prefix
)) == 0) {
2615 err
= xt
->set(value
, len
, &cvalue
, &clen
);
2621 err
= ext2fs_xattr_set(h
, key
, cvalue
, clen
);
2623 ret
= translate_error(fs
, ino
, err
);
2627 err
= ext2fs_xattrs_write(h
);
2629 ret
= translate_error(fs
, ino
, err
);
2633 ret
= update_ctime(fs
, ino
, NULL
);
2635 if (cvalue
!= value
)
2636 ext2fs_free_mem(&cvalue
);
2638 err
= ext2fs_xattrs_close(&h
);
2640 ret
= translate_error(fs
, ino
, err
);
2642 pthread_mutex_unlock(&ff
->bfl
);
2647 static int op_removexattr(const char *path
, const char *key
)
2649 struct fuse_context
*ctxt
= fuse_get_context();
2650 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2652 struct ext2_xattr_handle
*h
;
2657 FUSE2FS_CHECK_CONTEXT(ff
);
2659 pthread_mutex_lock(&ff
->bfl
);
2660 if (!EXT2_HAS_COMPAT_FEATURE(fs
->super
,
2661 EXT2_FEATURE_COMPAT_EXT_ATTR
)) {
2666 if (!fs_can_allocate(ff
, 1)) {
2671 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
2672 if (err
|| ino
== 0) {
2673 ret
= translate_error(fs
, 0, err
);
2676 dbg_printf("%s: ino=%d\n", __func__
, ino
);
2678 ret
= check_inum_access(fs
, ino
, W_OK
);
2682 err
= ext2fs_xattrs_open(fs
, ino
, &h
);
2684 ret
= translate_error(fs
, ino
, err
);
2688 err
= ext2fs_xattrs_read(h
);
2690 ret
= translate_error(fs
, ino
, err
);
2694 err
= ext2fs_xattr_remove(h
, key
);
2696 ret
= translate_error(fs
, ino
, err
);
2700 err
= ext2fs_xattrs_write(h
);
2702 ret
= translate_error(fs
, ino
, err
);
2706 ret
= update_ctime(fs
, ino
, NULL
);
2708 err
= ext2fs_xattrs_close(&h
);
2710 ret
= translate_error(fs
, ino
, err
);
2712 pthread_mutex_unlock(&ff
->bfl
);
2717 struct readdir_iter
{
2719 fuse_fill_dir_t func
;
2722 static int op_readdir_iter(ext2_ino_t dir
, int entry
,
2723 struct ext2_dir_entry
*dirent
, int offset
,
2724 int blocksize
, char *buf
, void *data
)
2726 struct readdir_iter
*i
= data
;
2727 char namebuf
[EXT2_NAME_LEN
+ 1];
2730 memcpy(namebuf
, dirent
->name
, dirent
->name_len
& 0xFF);
2731 namebuf
[dirent
->name_len
& 0xFF] = 0;
2732 ret
= i
->func(i
->buf
, namebuf
, NULL
, 0);
2734 return DIRENT_ABORT
;
2739 static int op_readdir(const char *path
, void *buf
, fuse_fill_dir_t fill_func
,
2740 off_t offset
, struct fuse_file_info
*fp
)
2742 struct fuse_context
*ctxt
= fuse_get_context();
2743 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2744 struct fuse2fs_file_handle
*fh
= (struct fuse2fs_file_handle
*)fp
->fh
;
2747 struct readdir_iter i
;
2750 FUSE2FS_CHECK_CONTEXT(ff
);
2752 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
2753 dbg_printf("%s: ino=%d\n", __func__
, fh
->ino
);
2754 pthread_mutex_lock(&ff
->bfl
);
2757 err
= ext2fs_dir_iterate2(fs
, fh
->ino
, 0, NULL
, op_readdir_iter
, &i
);
2759 ret
= translate_error(fs
, fh
->ino
, err
);
2763 if (fs_writeable(fs
)) {
2764 ret
= update_atime(fs
, fh
->ino
);
2769 pthread_mutex_unlock(&ff
->bfl
);
2773 static int op_access(const char *path
, int mask
)
2775 struct fuse_context
*ctxt
= fuse_get_context();
2776 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2782 FUSE2FS_CHECK_CONTEXT(ff
);
2784 dbg_printf("%s: path=%s mask=0x%x\n", __func__
, path
, mask
);
2785 pthread_mutex_lock(&ff
->bfl
);
2786 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
2787 if (err
|| ino
== 0) {
2788 ret
= translate_error(fs
, 0, err
);
2792 ret
= check_inum_access(fs
, ino
, mask
);
2797 pthread_mutex_unlock(&ff
->bfl
);
2801 static int op_create(const char *path
, mode_t mode
, struct fuse_file_info
*fp
)
2803 struct fuse_context
*ctxt
= fuse_get_context();
2804 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2806 ext2_ino_t parent
, child
;
2807 char *temp_path
= strdup(path
);
2811 struct ext2_inode_large inode
;
2814 FUSE2FS_CHECK_CONTEXT(ff
);
2816 dbg_printf("%s: path=%s mode=0%o\n", __func__
, path
, mode
);
2821 node_name
= strrchr(temp_path
, '/');
2830 pthread_mutex_lock(&ff
->bfl
);
2831 if (!fs_can_allocate(ff
, 1)) {
2836 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, temp_path
,
2839 ret
= translate_error(fs
, 0, err
);
2843 ret
= check_inum_access(fs
, parent
, W_OK
);
2849 filetype
= ext2_file_type(mode
);
2851 err
= ext2fs_new_inode(fs
, parent
, mode
, 0, &child
);
2853 ret
= translate_error(fs
, parent
, err
);
2857 dbg_printf("%s: creating ino=%d/name=%s in dir=%d\n", __func__
, child
,
2859 err
= ext2fs_link(fs
, parent
, node_name
, child
, filetype
);
2860 if (err
== EXT2_ET_DIR_NO_SPACE
) {
2861 err
= ext2fs_expand_dir(fs
, parent
);
2863 ret
= translate_error(fs
, parent
, err
);
2867 err
= ext2fs_link(fs
, parent
, node_name
, child
,
2871 ret
= translate_error(fs
, parent
, err
);
2875 ret
= update_mtime(fs
, parent
, NULL
);
2879 memset(&inode
, 0, sizeof(inode
));
2880 inode
.i_mode
= mode
;
2881 inode
.i_links_count
= 1;
2882 inode
.i_extra_isize
= sizeof(struct ext2_inode_large
) -
2883 EXT2_GOOD_OLD_INODE_SIZE
;
2884 if (fs
->super
->s_feature_incompat
& EXT3_FEATURE_INCOMPAT_EXTENTS
) {
2885 ext2_extent_handle_t handle
;
2887 inode
.i_flags
&= ~EXT4_EXTENTS_FL
;
2888 ret
= ext2fs_extent_open2(fs
, child
,
2889 (struct ext2_inode
*)&inode
, &handle
);
2892 ext2fs_extent_free(handle
);
2895 err
= ext2fs_write_new_inode(fs
, child
, (struct ext2_inode
*)&inode
);
2897 ret
= translate_error(fs
, child
, err
);
2901 inode
.i_generation
= ff
->next_generation
++;
2903 err
= ext2fs_write_inode_full(fs
, child
, (struct ext2_inode
*)&inode
,
2906 ret
= translate_error(fs
, child
, err
);
2910 ext2fs_inode_alloc_stats2(fs
, child
, 1, 0);
2912 ret
= __op_open(ff
, path
, fp
);
2916 pthread_mutex_unlock(&ff
->bfl
);
2922 static int op_ftruncate(const char *path
, off_t len
, struct fuse_file_info
*fp
)
2924 struct fuse_context
*ctxt
= fuse_get_context();
2925 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2926 struct fuse2fs_file_handle
*fh
= (struct fuse2fs_file_handle
*)fp
->fh
;
2932 FUSE2FS_CHECK_CONTEXT(ff
);
2934 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
2935 dbg_printf("%s: ino=%d len=%jd\n", __func__
, fh
->ino
, len
);
2936 pthread_mutex_lock(&ff
->bfl
);
2937 if (!fs_writeable(fs
)) {
2942 err
= ext2fs_file_open(fs
, fh
->ino
, fh
->open_flags
, &efp
);
2944 ret
= translate_error(fs
, fh
->ino
, err
);
2948 err
= ext2fs_file_set_size2(efp
, len
);
2950 ret
= translate_error(fs
, fh
->ino
, err
);
2955 err
= ext2fs_file_close(efp
);
2959 ret
= translate_error(fs
, fh
->ino
, err
);
2963 ret
= update_mtime(fs
, fh
->ino
, NULL
);
2968 pthread_mutex_unlock(&ff
->bfl
);
2972 static int op_fgetattr(const char *path
, struct stat
*statbuf
,
2973 struct fuse_file_info
*fp
)
2975 struct fuse_context
*ctxt
= fuse_get_context();
2976 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2978 struct fuse2fs_file_handle
*fh
= (struct fuse2fs_file_handle
*)fp
->fh
;
2981 FUSE2FS_CHECK_CONTEXT(ff
);
2983 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
2984 dbg_printf("%s: ino=%d\n", __func__
, fh
->ino
);
2985 pthread_mutex_lock(&ff
->bfl
);
2986 ret
= stat_inode(fs
, fh
->ino
, statbuf
);
2987 pthread_mutex_unlock(&ff
->bfl
);
2992 static int op_utimens(const char *path
, const struct timespec ctv
[2])
2994 struct fuse_context
*ctxt
= fuse_get_context();
2995 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
2996 struct timespec
*tv
= (struct timespec
*)ctv
;
3000 struct ext2_inode_large inode
;
3003 FUSE2FS_CHECK_CONTEXT(ff
);
3005 pthread_mutex_lock(&ff
->bfl
);
3006 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
3008 ret
= translate_error(fs
, 0, err
);
3011 dbg_printf("%s: ino=%d\n", __func__
, ino
);
3013 ret
= check_inum_access(fs
, ino
, W_OK
);
3017 memset(&inode
, 0, sizeof(inode
));
3018 err
= ext2fs_read_inode_full(fs
, ino
, (struct ext2_inode
*)&inode
,
3021 ret
= translate_error(fs
, ino
, err
);
3026 if (tv
[0].tv_nsec
== UTIME_NOW
)
3028 if (tv
[1].tv_nsec
== UTIME_NOW
)
3030 #endif /* UTIME_NOW */
3032 if (tv
[0].tv_nsec
!= UTIME_OMIT
)
3033 EXT4_INODE_SET_XTIME(i_atime
, tv
, &inode
);
3034 if (tv
[1].tv_nsec
!= UTIME_OMIT
)
3035 EXT4_INODE_SET_XTIME(i_mtime
, tv
+ 1, &inode
);
3036 #endif /* UTIME_OMIT */
3037 ret
= update_ctime(fs
, ino
, &inode
);
3041 err
= ext2fs_write_inode_full(fs
, ino
, (struct ext2_inode
*)&inode
,
3044 ret
= translate_error(fs
, ino
, err
);
3049 pthread_mutex_unlock(&ff
->bfl
);
3053 #ifdef SUPPORT_I_FLAGS
3054 static int ioctl_getflags(ext2_filsys fs
, struct fuse2fs_file_handle
*fh
,
3058 struct ext2_inode_large inode
;
3060 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
3061 dbg_printf("%s: ino=%d\n", __func__
, fh
->ino
);
3062 memset(&inode
, 0, sizeof(inode
));
3063 err
= ext2fs_read_inode_full(fs
, fh
->ino
, (struct ext2_inode
*)&inode
,
3066 return translate_error(fs
, fh
->ino
, err
);
3068 *(__u32
*)data
= inode
.i_flags
& EXT2_FL_USER_VISIBLE
;
3072 #define FUSE2FS_MODIFIABLE_IFLAGS \
3073 (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL | EXT2_NODUMP_FL | \
3074 EXT2_NOATIME_FL | EXT3_JOURNAL_DATA_FL | EXT2_DIRSYNC_FL | \
3077 static int ioctl_setflags(ext2_filsys fs
, struct fuse2fs_file_handle
*fh
,
3081 struct ext2_inode_large inode
;
3083 __u32 flags
= *(__u32
*)data
;
3084 struct fuse_context
*ctxt
= fuse_get_context();
3086 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
3087 dbg_printf("%s: ino=%d\n", __func__
, fh
->ino
);
3088 memset(&inode
, 0, sizeof(inode
));
3089 err
= ext2fs_read_inode_full(fs
, fh
->ino
, (struct ext2_inode
*)&inode
,
3092 return translate_error(fs
, fh
->ino
, err
);
3094 if (ctxt
->uid
!= 0 && inode
.i_uid
!= ctxt
->uid
)
3097 if ((inode
.i_flags
^ flags
) & ~FUSE2FS_MODIFIABLE_IFLAGS
)
3100 inode
.i_flags
= (inode
.i_flags
& ~FUSE2FS_MODIFIABLE_IFLAGS
) |
3101 (flags
& FUSE2FS_MODIFIABLE_IFLAGS
);
3103 ret
= update_ctime(fs
, fh
->ino
, &inode
);
3107 err
= ext2fs_write_inode_full(fs
, fh
->ino
, (struct ext2_inode
*)&inode
,
3110 return translate_error(fs
, fh
->ino
, err
);
3115 static int ioctl_getversion(ext2_filsys fs
, struct fuse2fs_file_handle
*fh
,
3119 struct ext2_inode_large inode
;
3121 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
3122 dbg_printf("%s: ino=%d\n", __func__
, fh
->ino
);
3123 memset(&inode
, 0, sizeof(inode
));
3124 err
= ext2fs_read_inode_full(fs
, fh
->ino
, (struct ext2_inode
*)&inode
,
3127 return translate_error(fs
, fh
->ino
, err
);
3129 *(__u32
*)data
= inode
.i_generation
;
3133 static int ioctl_setversion(ext2_filsys fs
, struct fuse2fs_file_handle
*fh
,
3137 struct ext2_inode_large inode
;
3139 __u32 generation
= *(__u32
*)data
;
3140 struct fuse_context
*ctxt
= fuse_get_context();
3142 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
3143 dbg_printf("%s: ino=%d\n", __func__
, fh
->ino
);
3144 memset(&inode
, 0, sizeof(inode
));
3145 err
= ext2fs_read_inode_full(fs
, fh
->ino
, (struct ext2_inode
*)&inode
,
3148 return translate_error(fs
, fh
->ino
, err
);
3150 if (ctxt
->uid
!= 0 && inode
.i_uid
!= ctxt
->uid
)
3153 inode
.i_generation
= generation
;
3155 ret
= update_ctime(fs
, fh
->ino
, &inode
);
3159 err
= ext2fs_write_inode_full(fs
, fh
->ino
, (struct ext2_inode
*)&inode
,
3162 return translate_error(fs
, fh
->ino
, err
);
3166 #endif /* SUPPORT_I_FLAGS */
3169 static int ioctl_fitrim(ext2_filsys fs
, struct fuse2fs_file_handle
*fh
,
3172 struct fstrim_range
*fr
= data
;
3173 blk64_t start
, end
, max_blocks
, b
, cleared
;
3176 start
= fr
->start
/ fs
->blocksize
;
3177 end
= (fr
->start
+ fr
->len
- 1) / fs
->blocksize
;
3178 dbg_printf("%s: start=%llu end=%llu\n", __func__
, start
, end
);
3180 if (start
< fs
->super
->s_first_data_block
)
3181 start
= fs
->super
->s_first_data_block
;
3182 if (start
>= ext2fs_blocks_count(fs
->super
))
3183 start
= ext2fs_blocks_count(fs
->super
) - 1;
3185 if (end
< fs
->super
->s_first_data_block
)
3186 end
= fs
->super
->s_first_data_block
;
3187 if (end
>= ext2fs_blocks_count(fs
->super
))
3188 end
= ext2fs_blocks_count(fs
->super
) - 1;
3191 max_blocks
= 2048ULL * 1024 * 1024 / fs
->blocksize
;
3194 while (start
<= end
) {
3195 err
= ext2fs_find_first_zero_block_bitmap2(fs
->block_map
,
3196 start
, end
, &start
);
3200 return translate_error(fs
, fh
->ino
, err
);
3202 b
= start
+ max_blocks
< end
? start
+ max_blocks
: end
;
3203 err
= ext2fs_find_first_set_block_bitmap2(fs
->block_map
,
3205 if (err
&& err
!= ENOENT
)
3206 return translate_error(fs
, fh
->ino
, err
);
3207 if (b
- start
>= fr
->minlen
) {
3208 err
= io_channel_discard(fs
->io
, start
, b
- start
);
3210 return translate_error(fs
, fh
->ino
, err
);
3211 cleared
+= b
- start
;
3212 fr
->len
= cleared
* fs
->blocksize
;
3221 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
3222 static int op_ioctl(const char *path
, int cmd
, void *arg
,
3223 struct fuse_file_info
*fp
, unsigned int flags
, void *data
)
3225 struct fuse_context
*ctxt
= fuse_get_context();
3226 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
3227 struct fuse2fs_file_handle
*fh
= (struct fuse2fs_file_handle
*)fp
->fh
;
3231 FUSE2FS_CHECK_CONTEXT(ff
);
3233 pthread_mutex_lock(&ff
->bfl
);
3235 #ifdef SUPPORT_I_FLAGS
3236 case EXT2_IOC_GETFLAGS
:
3237 ret
= ioctl_getflags(fs
, fh
, data
);
3239 case EXT2_IOC_SETFLAGS
:
3240 ret
= ioctl_setflags(fs
, fh
, data
);
3242 case EXT2_IOC_GETVERSION
:
3243 ret
= ioctl_getversion(fs
, fh
, data
);
3245 case EXT2_IOC_SETVERSION
:
3246 ret
= ioctl_setversion(fs
, fh
, data
);
3251 ret
= ioctl_fitrim(fs
, fh
, data
);
3255 dbg_printf("%s: Unknown ioctl %d\n", __func__
, cmd
);
3258 pthread_mutex_unlock(&ff
->bfl
);
3262 #endif /* FUSE 28 */
3264 static int op_bmap(const char *path
, size_t blocksize
, uint64_t *idx
)
3266 struct fuse_context
*ctxt
= fuse_get_context();
3267 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
3273 FUSE2FS_CHECK_CONTEXT(ff
);
3275 pthread_mutex_lock(&ff
->bfl
);
3276 err
= ext2fs_namei(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, path
, &ino
);
3278 ret
= translate_error(fs
, 0, err
);
3281 dbg_printf("%s: ino=%d blk=%"PRIu64
"\n", __func__
, ino
, *idx
);
3283 err
= ext2fs_bmap2(fs
, ino
, NULL
, NULL
, 0, *idx
, 0, (blk64_t
*)idx
);
3285 ret
= translate_error(fs
, ino
, err
);
3290 pthread_mutex_unlock(&ff
->bfl
);
3294 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
3295 # ifdef SUPPORT_FALLOCATE
3296 static int fallocate_helper(struct fuse_file_info
*fp
, int mode
, off_t offset
,
3299 struct fuse_context
*ctxt
= fuse_get_context();
3300 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
3301 struct fuse2fs_file_handle
*fh
= (struct fuse2fs_file_handle
*)fp
->fh
;
3303 struct ext2_inode_large inode
;
3309 FUSE2FS_CHECK_CONTEXT(ff
);
3311 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
3312 start
= offset
/ fs
->blocksize
;
3313 end
= (offset
+ len
- 1) / fs
->blocksize
;
3314 dbg_printf("%s: ino=%d mode=0x%x start=%jd end=%llu\n", __func__
,
3315 fh
->ino
, mode
, offset
/ fs
->blocksize
, end
);
3316 if (!fs_can_allocate(ff
, len
/ fs
->blocksize
))
3319 memset(&inode
, 0, sizeof(inode
));
3320 err
= ext2fs_read_inode_full(fs
, fh
->ino
, (struct ext2_inode
*)&inode
,
3324 fsize
= EXT2_I_SIZE(&inode
);
3326 /* Allocate a bunch of blocks */
3327 flags
= (mode
& FL_KEEP_SIZE_FLAG
? 0 :
3328 EXT2_FALLOCATE_INIT_BEYOND_EOF
);
3329 err
= ext2fs_fallocate(fs
, flags
, fh
->ino
,
3330 (struct ext2_inode
*)&inode
,
3331 ~0ULL, start
, end
- start
+ 1);
3332 if (err
&& err
!= EXT2_ET_BLOCK_ALLOC_FAIL
)
3333 return translate_error(fs
, fh
->ino
, err
);
3336 if (!(mode
& FL_KEEP_SIZE_FLAG
)) {
3337 if (offset
+ len
> fsize
) {
3338 err
= ext2fs_inode_size_set(fs
,
3339 (struct ext2_inode
*)&inode
,
3342 return translate_error(fs
, fh
->ino
, err
);
3346 err
= update_mtime(fs
, fh
->ino
, &inode
);
3350 err
= ext2fs_write_inode_full(fs
, fh
->ino
, (struct ext2_inode
*)&inode
,
3353 return translate_error(fs
, fh
->ino
, err
);
3358 static errcode_t
clean_block_middle(ext2_filsys fs
, ext2_ino_t ino
,
3359 struct ext2_inode_large
*inode
, off_t offset
,
3360 off_t len
, char **buf
)
3367 residue
= offset
% fs
->blocksize
;
3372 err
= ext2fs_get_mem(fs
->blocksize
, buf
);
3377 err
= ext2fs_bmap2(fs
, ino
, (struct ext2_inode
*)inode
, *buf
, 0,
3378 offset
/ fs
->blocksize
, &retflags
, &blk
);
3381 if (!blk
|| (retflags
& BMAP_RET_UNINIT
))
3384 err
= io_channel_read_blk(fs
->io
, blk
, 1, *buf
);
3388 memset(*buf
+ residue
, 0, len
);
3390 return io_channel_write_blk(fs
->io
, blk
, 1, *buf
);
3393 static errcode_t
clean_block_edge(ext2_filsys fs
, ext2_ino_t ino
,
3394 struct ext2_inode_large
*inode
, off_t offset
,
3395 int clean_before
, char **buf
)
3402 residue
= offset
% fs
->blocksize
;
3407 err
= ext2fs_get_mem(fs
->blocksize
, buf
);
3412 err
= ext2fs_bmap2(fs
, ino
, (struct ext2_inode
*)inode
, *buf
, 0,
3413 offset
/ fs
->blocksize
, &retflags
, &blk
);
3417 err
= io_channel_read_blk(fs
->io
, blk
, 1, *buf
);
3420 if (!blk
|| (retflags
& BMAP_RET_UNINIT
))
3424 memset(*buf
, 0, residue
);
3426 memset(*buf
+ residue
, 0, fs
->blocksize
- residue
);
3428 return io_channel_write_blk(fs
->io
, blk
, 1, *buf
);
3431 static int punch_helper(struct fuse_file_info
*fp
, int mode
, off_t offset
,
3434 struct fuse_context
*ctxt
= fuse_get_context();
3435 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
3436 struct fuse2fs_file_handle
*fh
= (struct fuse2fs_file_handle
*)fp
->fh
;
3438 struct ext2_inode_large inode
;
3443 FUSE2FS_CHECK_CONTEXT(ff
);
3445 FUSE2FS_CHECK_MAGIC(fs
, fh
, FUSE2FS_FILE_MAGIC
);
3446 dbg_printf("%s: offset=%jd len=%jd\n", __func__
, offset
, len
);
3448 /* kernel ext4 punch requires this flag to be set */
3449 if (!(mode
& FL_KEEP_SIZE_FLAG
))
3452 /* Punch out a bunch of blocks */
3453 start
= (offset
+ fs
->blocksize
- 1) / fs
->blocksize
;
3454 end
= (offset
+ len
- fs
->blocksize
) / fs
->blocksize
;
3455 dbg_printf("%s: ino=%d mode=0x%x start=%llu end=%llu\n", __func__
,
3456 fh
->ino
, mode
, start
, end
);
3458 memset(&inode
, 0, sizeof(inode
));
3459 err
= ext2fs_read_inode_full(fs
, fh
->ino
, (struct ext2_inode
*)&inode
,
3462 return translate_error(fs
, fh
->ino
, err
);
3464 /* Zero everything before the first block and after the last block */
3465 if ((offset
/ fs
->blocksize
) == ((offset
+ len
) / fs
->blocksize
))
3466 err
= clean_block_middle(fs
, fh
->ino
, &inode
, offset
,
3469 err
= clean_block_edge(fs
, fh
->ino
, &inode
, offset
, 0, &buf
);
3471 err
= clean_block_edge(fs
, fh
->ino
, &inode
,
3472 offset
+ len
, 1, &buf
);
3475 ext2fs_free_mem(&buf
);
3477 return translate_error(fs
, fh
->ino
, err
);
3479 /* Unmap full blocks in the middle */
3481 err
= ext2fs_punch(fs
, fh
->ino
, (struct ext2_inode
*)&inode
,
3484 return translate_error(fs
, fh
->ino
, err
);
3487 err
= update_mtime(fs
, fh
->ino
, &inode
);
3491 err
= ext2fs_write_inode_full(fs
, fh
->ino
, (struct ext2_inode
*)&inode
,
3494 return translate_error(fs
, fh
->ino
, err
);
3499 static int op_fallocate(const char *path
, int mode
, off_t offset
, off_t len
,
3500 struct fuse_file_info
*fp
)
3502 struct fuse_context
*ctxt
= fuse_get_context();
3503 struct fuse2fs
*ff
= (struct fuse2fs
*)ctxt
->private_data
;
3504 ext2_filsys fs
= ff
->fs
;
3507 /* Catch unknown flags */
3508 if (mode
& ~(FL_PUNCH_HOLE_FLAG
| FL_KEEP_SIZE_FLAG
))
3511 pthread_mutex_lock(&ff
->bfl
);
3512 if (!fs_writeable(fs
)) {
3516 if (mode
& FL_PUNCH_HOLE_FLAG
)
3517 ret
= punch_helper(fp
, mode
, offset
, len
);
3519 ret
= fallocate_helper(fp
, mode
, offset
, len
);
3521 pthread_mutex_unlock(&ff
->bfl
);
3525 # endif /* SUPPORT_FALLOCATE */
3526 #endif /* FUSE 29 */
3528 static struct fuse_operations fs_ops
= {
3530 .destroy
= op_destroy
,
3531 .getattr
= op_getattr
,
3532 .readlink
= op_readlink
,
3535 .unlink
= op_unlink
,
3537 .symlink
= op_symlink
,
3538 .rename
= op_rename
,
3542 .truncate
= op_truncate
,
3546 .statfs
= op_statfs
,
3547 .release
= op_release
,
3549 .setxattr
= op_setxattr
,
3550 .getxattr
= op_getxattr
,
3551 .listxattr
= op_listxattr
,
3552 .removexattr
= op_removexattr
,
3554 .readdir
= op_readdir
,
3555 .releasedir
= op_release
,
3556 .fsyncdir
= op_fsync
,
3557 .access
= op_access
,
3558 .create
= op_create
,
3559 .ftruncate
= op_ftruncate
,
3560 .fgetattr
= op_fgetattr
,
3561 .utimens
= op_utimens
,
3562 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
3563 # if defined(UTIME_NOW) || defined(UTIME_OMIT)
3564 .flag_utime_omit_ok
= 1,
3572 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
3574 .flag_nullpath_ok
= 1,
3576 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
3578 # ifdef SUPPORT_FALLOCATE
3579 .fallocate
= op_fallocate
,
3584 static int get_random_bytes(void *p
, size_t sz
)
3589 fd
= open("/dev/random", O_RDONLY
);
3591 perror("/dev/random");
3595 r
= read(fd
, p
, sz
);
3601 static void print_help(const char *progname
)
3603 printf(_("Usage: %s dev mntpt [-o options] [fuse_args]\n"), progname
);
3606 int main(int argc
, char *argv
[])
3609 char *tok
, *arg
, *logfile
;
3611 int readwrite
= 1, panic_on_error
= 0, minixdf
= 0;
3613 char extra_args
[BUFSIZ
];
3614 int ret
= 0, flags
= EXT2_FLAG_64BITS
| EXT2_FLAG_EXCLUSIVE
;
3617 print_help(argv
[0]);
3621 for (i
= 1; i
< argc
; i
++) {
3622 if (strcmp(argv
[i
], "--help") == 0) {
3623 print_help(argv
[0]);
3628 for (i
= 1; i
< argc
- 1; i
++) {
3629 if (strcmp(argv
[i
], "-o"))
3632 while ((tok
= strtok(arg
, ","))) {
3634 if (!strcmp(tok
, "ro"))
3636 else if (!strcmp(tok
, "errors=panic"))
3638 else if (!strcmp(tok
, "minixdf"))
3644 printf("%s", _("Mounting read-only.\n"));
3647 setlocale(LC_MESSAGES
, "");
3648 setlocale(LC_CTYPE
, "");
3649 bindtextdomain(NLS_CAT_NAME
, LOCALEDIR
);
3650 textdomain(NLS_CAT_NAME
);
3651 set_com_err_gettext(gettext
);
3653 add_error_table(&et_ext2_error_table
);
3655 ff
= calloc(1, sizeof(*ff
));
3660 ff
->magic
= FUSE2FS_MAGIC
;
3661 ff
->panic_on_error
= panic_on_error
;
3662 ff
->minixdf
= minixdf
;
3664 /* Set up error logging */
3665 logfile
= getenv("FUSE2FS_LOGFILE");
3667 ff
->err_fp
= fopen(logfile
, "a");
3673 ff
->err_fp
= stderr
;
3675 /* Will we allow users to allocate every last block? */
3676 if (getenv("FUSE2FS_ALLOC_ALL_BLOCKS")) {
3677 printf(_("%s: Allowing users to allocate all blocks. "
3678 "This is dangerous!\n"), argv
[1]);
3679 ff
->alloc_all_blocks
= 1;
3682 /* Start up the fs (while we still can use stdout) */
3685 flags
|= EXT2_FLAG_RW
;
3686 err
= ext2fs_open2(argv
[1], NULL
, flags
, 0, 0, unix_io_manager
,
3689 printf(_("%s: %s.\n"), argv
[1], error_message(err
));
3690 printf(_("Please run e2fsck -fy %s.\n"), argv
[1]);
3694 global_fs
->priv_data
= ff
;
3697 if (EXT2_HAS_INCOMPAT_FEATURE(global_fs
->super
,
3698 EXT3_FEATURE_INCOMPAT_RECOVER
)) {
3700 printf(_("%s: recovering journal\n"), argv
[1]);
3701 err
= ext2fs_run_ext3_journal(&global_fs
);
3703 printf(_("%s: %s.\n"), argv
[1],
3704 error_message(err
));
3705 printf(_("Please run e2fsck -fy %s.\n"),
3709 global_fs
->super
->s_feature_incompat
&=
3710 ~EXT3_FEATURE_INCOMPAT_RECOVER
;
3711 ext2fs_mark_super_dirty(global_fs
);
3713 printf("%s", _("Journal needs recovery; running "
3714 "`e2fsck -E journal_only' is required.\n"));
3720 if (EXT2_HAS_COMPAT_FEATURE(global_fs
->super
,
3721 EXT3_FEATURE_COMPAT_HAS_JOURNAL
))
3722 printf(_("%s: Writing to the journal is not supported.\n"),
3724 err
= ext2fs_read_inode_bitmap(global_fs
);
3726 translate_error(global_fs
, 0, err
);
3729 err
= ext2fs_read_block_bitmap(global_fs
);
3731 translate_error(global_fs
, 0, err
);
3736 if (!(global_fs
->super
->s_state
& EXT2_VALID_FS
))
3737 printf("%s", _("Warning: Mounting unchecked fs, running e2fsck "
3738 "is recommended.\n"));
3739 if (global_fs
->super
->s_max_mnt_count
> 0 &&
3740 global_fs
->super
->s_mnt_count
>= global_fs
->super
->s_max_mnt_count
)
3741 printf("%s", _("Warning: Maximal mount count reached, running "
3742 "e2fsck is recommended.\n"));
3743 if (global_fs
->super
->s_checkinterval
> 0 &&
3744 global_fs
->super
->s_lastcheck
+
3745 global_fs
->super
->s_checkinterval
<= time(0))
3746 printf("%s", _("Warning: Check time reached; running e2fsck "
3747 "is recommended.\n"));
3748 if (global_fs
->super
->s_last_orphan
)
3750 _("Orphans detected; running e2fsck is recommended.\n"));
3752 if (global_fs
->super
->s_state
& EXT2_ERROR_FS
) {
3754 _("Errors detected; running e2fsck is required.\n"));
3758 /* Initialize generation counter */
3759 get_random_bytes(&ff
->next_generation
, sizeof(unsigned int));
3761 /* Stuff in some fuse parameters of our own */
3762 snprintf(extra_args
, BUFSIZ
, "-okernel_cache,subtype=ext4,use_ino,"
3763 "fsname=%s,attr_timeout=0,allow_other" FUSE_PLATFORM_OPTS
,
3767 argv
[2] = extra_args
;
3769 pthread_mutex_init(&ff
->bfl
, NULL
);
3770 fuse_main(argc
, argv
, &fs_ops
, ff
);
3771 pthread_mutex_destroy(&ff
->bfl
);
3775 err
= ext2fs_close(global_fs
);
3777 com_err(argv
[0], err
, "while closing fs");
3785 static int __translate_error(ext2_filsys fs
, errcode_t err
, ext2_ino_t ino
,
3786 const char *file
, int line
)
3788 struct timespec now
;
3790 struct fuse2fs
*ff
= fs
->priv_data
;
3793 /* Translate ext2 error to unix error code */
3794 if (err
< EXT2_ET_BASE
)
3795 goto no_translation
;
3797 case EXT2_ET_NO_MEMORY
:
3798 case EXT2_ET_TDB_ERR_OOM
:
3801 case EXT2_ET_INVALID_ARGUMENT
:
3802 case EXT2_ET_LLSEEK_FAILED
:
3805 case EXT2_ET_NO_DIRECTORY
:
3808 case EXT2_ET_FILE_NOT_FOUND
:
3811 case EXT2_ET_DIR_NO_SPACE
:
3813 case EXT2_ET_TOOSMALL
:
3814 case EXT2_ET_BLOCK_ALLOC_FAIL
:
3815 case EXT2_ET_INODE_ALLOC_FAIL
:
3816 case EXT2_ET_EA_NO_SPACE
:
3819 case EXT2_ET_SYMLINK_LOOP
:
3822 case EXT2_ET_FILE_TOO_BIG
:
3825 case EXT2_ET_TDB_ERR_EXISTS
:
3826 case EXT2_ET_FILE_EXISTS
:
3829 case EXT2_ET_MMP_FAILED
:
3830 case EXT2_ET_MMP_FSCK_ON
:
3833 case EXT2_ET_EA_KEY_NOT_FOUND
:
3840 /* Sometimes fuse returns a garbage file handle pointer to us... */
3841 case EXT2_ET_MAGIC_EXT2_FILE
:
3844 case EXT2_ET_UNIMPLEMENTED
:
3858 fprintf(ff
->err_fp
, "FUSE2FS (%s): %s (inode #%d) at %s:%d.\n",
3859 fs
&& fs
->device_name
? fs
->device_name
: "???",
3860 error_message(err
), ino
, file
, line
);
3862 fprintf(ff
->err_fp
, "FUSE2FS (%s): %s at %s:%d.\n",
3863 fs
&& fs
->device_name
? fs
->device_name
: "???",
3864 error_message(err
), file
, line
);
3867 /* Make a note in the error log */
3869 fs
->super
->s_last_error_time
= now
.tv_sec
;
3870 fs
->super
->s_last_error_ino
= ino
;
3871 fs
->super
->s_last_error_line
= line
;
3872 fs
->super
->s_last_error_block
= err
; /* Yeah... */
3873 strncpy((char *)fs
->super
->s_last_error_func
, file
,
3874 sizeof(fs
->super
->s_last_error_func
));
3875 if (fs
->super
->s_first_error_time
== 0) {
3876 fs
->super
->s_first_error_time
= now
.tv_sec
;
3877 fs
->super
->s_first_error_ino
= ino
;
3878 fs
->super
->s_first_error_line
= line
;
3879 fs
->super
->s_first_error_block
= err
;
3880 strncpy((char *)fs
->super
->s_first_error_func
, file
,
3881 sizeof(fs
->super
->s_first_error_func
));
3884 fs
->super
->s_error_count
++;
3885 ext2fs_mark_super_dirty(fs
);
3887 if (ff
->panic_on_error
)