Whamcloud - gitweb
Fix compile error and warnings for old gcc versions
[tools/e2fsprogs.git] / misc / fuse2fs.c
1 /*
2  * fuse2fs.c - FUSE server for e2fsprogs.
3  *
4  * Copyright (C) 2014 Oracle.
5  *
6  * %Begin-Header%
7  * This file may be redistributed under the terms of the GNU Public
8  * License.
9  * %End-Header%
10  */
11 #define _FILE_OFFSET_BITS 64
12 #define FUSE_USE_VERSION 29
13 #ifndef _GNU_SOURCE
14 #define _GNU_SOURCE
15 #endif
16 #include "config.h"
17 #include <pthread.h>
18 #ifdef __linux__
19 # include <linux/fs.h>
20 # include <linux/falloc.h>
21 # include <linux/xattr.h>
22 # define FUSE_PLATFORM_OPTS     ",nonempty,big_writes"
23 # ifdef HAVE_SYS_ACL_H
24 #  define TRANSLATE_LINUX_ACLS
25 # endif
26 #else
27 # define FUSE_PLATFORM_OPTS     ""
28 #endif
29 #ifdef TRANSLATE_LINUX_ACLS
30 # include <sys/acl.h>
31 #endif
32 #include <sys/ioctl.h>
33 #include <unistd.h>
34 #include <fuse.h>
35 #include <inttypes.h>
36 #include "ext2fs/ext2fs.h"
37 #include "ext2fs/ext2_fs.h"
38
39 #include "../version.h"
40
41 #ifdef ENABLE_NLS
42 #include <libintl.h>
43 #include <locale.h>
44 #define _(a) (gettext(a))
45 #ifdef gettext_noop
46 #define N_(a) gettext_noop(a)
47 #else
48 #define N_(a) (a)
49 #endif
50 #define P_(singular, plural, n) (ngettext(singular, plural, n))
51 #ifndef NLS_CAT_NAME
52 #define NLS_CAT_NAME "e2fsprogs"
53 #endif
54 #ifndef LOCALEDIR
55 #define LOCALEDIR "/usr/share/locale"
56 #endif
57 #else
58 #define _(a) (a)
59 #define N_(a) a
60 #define P_(singular, plural, n) ((n) == 1 ? (singular) : (plural))
61 #endif
62
63 static ext2_filsys global_fs; /* Try not to use this directly */
64
65 #undef DEBUG
66
67 #ifdef DEBUG
68 # define dbg_printf(f, a...)  do {printf("FUSE2FS-" f, ## a); \
69         fflush(stdout); \
70 } while (0)
71 #else
72 # define dbg_printf(f, a...)
73 #endif
74
75 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
76 # ifdef _IOR
77 #  ifdef _IOW
78 #   define SUPPORT_I_FLAGS
79 #  endif
80 # endif
81 #endif
82
83 #ifdef FALLOC_FL_KEEP_SIZE
84 # define FL_KEEP_SIZE_FLAG FALLOC_FL_KEEP_SIZE
85 # define SUPPORT_FALLOCATE
86 #else
87 # define FL_KEEP_SIZE_FLAG (0)
88 #endif
89
90 #ifdef FALLOC_FL_PUNCH_HOLE
91 # define FL_PUNCH_HOLE_FLAG FALLOC_FL_PUNCH_HOLE
92 #else
93 # define FL_PUNCH_HOLE_FLAG (0)
94 #endif
95
96 errcode_t ext2fs_run_ext3_journal(ext2_filsys *fs);
97
98 #ifdef CONFIG_JBD_DEBUG         /* Enabled by configure --enable-jbd-debug */
99 int journal_enable_debug = -1;
100 #endif
101
102 /* ACL translation stuff */
103 #ifdef TRANSLATE_LINUX_ACLS
104 /*
105  * Copied from acl_ea.h in libacl source; ACLs have to be sent to and from fuse
106  * in this format... at least on Linux.
107  */
108 #define ACL_EA_ACCESS           "system.posix_acl_access"
109 #define ACL_EA_DEFAULT          "system.posix_acl_default"
110
111 #define ACL_EA_VERSION          0x0002
112
113 typedef struct {
114         u_int16_t       e_tag;
115         u_int16_t       e_perm;
116         u_int32_t       e_id;
117 } acl_ea_entry;
118
119 typedef struct {
120         u_int32_t       a_version;
121 #if __GNUC_PREREQ (4, 8)
122 #pragma GCC diagnostic push
123 #pragma GCC diagnostic ignored "-Wpedantic"
124 #endif
125         acl_ea_entry    a_entries[0];
126 #if __GNUC_PREREQ (4, 8)
127 #pragma GCC diagnostic pop
128 #endif
129 } acl_ea_header;
130
131 static inline size_t acl_ea_size(int count)
132 {
133         return sizeof(acl_ea_header) + count * sizeof(acl_ea_entry);
134 }
135
136 static inline int acl_ea_count(size_t size)
137 {
138         if (size < sizeof(acl_ea_header))
139                 return -1;
140         size -= sizeof(acl_ea_header);
141         if (size % sizeof(acl_ea_entry))
142                 return -1;
143         return size / sizeof(acl_ea_entry);
144 }
145
146 /*
147  * ext4 ACL structures, copied from fs/ext4/acl.h.
148  */
149 #define EXT4_ACL_VERSION        0x0001
150
151 typedef struct {
152         __u16           e_tag;
153         __u16           e_perm;
154         __u32           e_id;
155 } ext4_acl_entry;
156
157 typedef struct {
158         __u16           e_tag;
159         __u16           e_perm;
160 } ext4_acl_entry_short;
161
162 typedef struct {
163         __u32           a_version;
164 } ext4_acl_header;
165
166 static inline size_t ext4_acl_size(int count)
167 {
168         if (count <= 4) {
169                 return sizeof(ext4_acl_header) +
170                        count * sizeof(ext4_acl_entry_short);
171         } else {
172                 return sizeof(ext4_acl_header) +
173                        4 * sizeof(ext4_acl_entry_short) +
174                        (count - 4) * sizeof(ext4_acl_entry);
175         }
176 }
177
178 static inline int ext4_acl_count(size_t size)
179 {
180         ssize_t s;
181
182         size -= sizeof(ext4_acl_header);
183         s = size - 4 * sizeof(ext4_acl_entry_short);
184         if (s < 0) {
185                 if (size % sizeof(ext4_acl_entry_short))
186                         return -1;
187                 return size / sizeof(ext4_acl_entry_short);
188         }
189         if (s % sizeof(ext4_acl_entry))
190                 return -1;
191         return s / sizeof(ext4_acl_entry) + 4;
192 }
193
194 static errcode_t fuse_to_ext4_acl(acl_ea_header *facl, size_t facl_sz,
195                                   ext4_acl_header **eacl, size_t *eacl_sz)
196 {
197         int i, facl_count;
198         ext4_acl_header *h;
199         size_t h_sz;
200         ext4_acl_entry *e;
201         acl_ea_entry *a;
202         unsigned char *hptr;
203         errcode_t err;
204
205         facl_count = acl_ea_count(facl_sz);
206         h_sz = ext4_acl_size(facl_count);
207         if (facl_count < 0 || facl->a_version != ACL_EA_VERSION)
208                 return EXT2_ET_INVALID_ARGUMENT;
209
210         err = ext2fs_get_mem(h_sz, &h);
211         if (err)
212                 return err;
213
214         h->a_version = ext2fs_cpu_to_le32(EXT4_ACL_VERSION);
215         hptr = (unsigned char *) (h + 1);
216         for (i = 0, a = facl->a_entries; i < facl_count; i++, a++) {
217                 e = (ext4_acl_entry *) hptr;
218                 e->e_tag = ext2fs_cpu_to_le16(a->e_tag);
219                 e->e_perm = ext2fs_cpu_to_le16(a->e_perm);
220
221                 switch (a->e_tag) {
222                 case ACL_USER:
223                 case ACL_GROUP:
224                         e->e_id = ext2fs_cpu_to_le32(a->e_id);
225                         hptr += sizeof(ext4_acl_entry);
226                         break;
227                 case ACL_USER_OBJ:
228                 case ACL_GROUP_OBJ:
229                 case ACL_MASK:
230                 case ACL_OTHER:
231                         hptr += sizeof(ext4_acl_entry_short);
232                         break;
233                 default:
234                         err = EXT2_ET_INVALID_ARGUMENT;
235                         goto out;
236                 }
237         }
238
239         *eacl = h;
240         *eacl_sz = h_sz;
241         return err;
242 out:
243         ext2fs_free_mem(&h);
244         return err;
245 }
246
247 static errcode_t ext4_to_fuse_acl(acl_ea_header **facl, size_t *facl_sz,
248                                   ext4_acl_header *eacl, size_t eacl_sz)
249 {
250         int i, eacl_count;
251         acl_ea_header *f;
252         ext4_acl_entry *e;
253         acl_ea_entry *a;
254         size_t f_sz;
255         unsigned char *hptr;
256         errcode_t err;
257
258         eacl_count = ext4_acl_count(eacl_sz);
259         f_sz = acl_ea_size(eacl_count);
260         if (eacl_count < 0 ||
261             eacl->a_version != ext2fs_cpu_to_le32(EXT4_ACL_VERSION))
262                 return EXT2_ET_INVALID_ARGUMENT;
263
264         err = ext2fs_get_mem(f_sz, &f);
265         if (err)
266                 return err;
267
268         f->a_version = ACL_EA_VERSION;
269         hptr = (unsigned char *) (eacl + 1);
270         for (i = 0, a = f->a_entries; i < eacl_count; i++, a++) {
271                 e = (ext4_acl_entry *) hptr;
272                 a->e_tag = ext2fs_le16_to_cpu(e->e_tag);
273                 a->e_perm = ext2fs_le16_to_cpu(e->e_perm);
274
275                 switch (a->e_tag) {
276                 case ACL_USER:
277                 case ACL_GROUP:
278                         a->e_id = ext2fs_le32_to_cpu(e->e_id);
279                         hptr += sizeof(ext4_acl_entry);
280                         break;
281                 case ACL_USER_OBJ:
282                 case ACL_GROUP_OBJ:
283                 case ACL_MASK:
284                 case ACL_OTHER:
285                         hptr += sizeof(ext4_acl_entry_short);
286                         break;
287                 default:
288                         err = EXT2_ET_INVALID_ARGUMENT;
289                         goto out;
290                 }
291         }
292
293         *facl = f;
294         *facl_sz = f_sz;
295         return err;
296 out:
297         ext2fs_free_mem(&f);
298         return err;
299 }
300 #endif /* TRANSLATE_LINUX_ACLS */
301
302 /*
303  * ext2_file_t contains a struct inode, so we can't leave files open.
304  * Use this as a proxy instead.
305  */
306 #define FUSE2FS_FILE_MAGIC      (0xEF53DEAFUL)
307 struct fuse2fs_file_handle {
308         unsigned long magic;
309         ext2_ino_t ino;
310         int open_flags;
311 };
312
313 /* Main program context */
314 #define FUSE2FS_MAGIC           (0xEF53DEADUL)
315 struct fuse2fs {
316         unsigned long magic;
317         ext2_filsys fs;
318         pthread_mutex_t bfl;
319         char *device;
320         int ro;
321         int debug;
322         int no_default_opts;
323         int panic_on_error;
324         int minixdf;
325         int alloc_all_blocks;
326         FILE *err_fp;
327         unsigned int next_generation;
328 };
329
330 #define FUSE2FS_CHECK_MAGIC(fs, ptr, num) do {if ((ptr)->magic != (num)) \
331         return translate_error((fs), 0, EXT2_ET_MAGIC_EXT2_FILE); \
332 } while (0)
333
334 #define FUSE2FS_CHECK_CONTEXT(ptr) do {if ((ptr)->magic != FUSE2FS_MAGIC) \
335         return translate_error(global_fs, 0, EXT2_ET_BAD_MAGIC); \
336 } while (0)
337
338 static int __translate_error(ext2_filsys fs, errcode_t err, ext2_ino_t ino,
339                              const char *file, int line);
340 #define translate_error(fs, ino, err) __translate_error((fs), (err), (ino), \
341                         __FILE__, __LINE__)
342
343 /* for macosx */
344 #ifndef W_OK
345 #  define W_OK 2
346 #endif
347
348 #ifndef R_OK
349 #  define R_OK 4
350 #endif
351
352 #define EXT4_EPOCH_BITS 2
353 #define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1)
354 #define EXT4_NSEC_MASK  (~0UL << EXT4_EPOCH_BITS)
355
356 /*
357  * Extended fields will fit into an inode if the filesystem was formatted
358  * with large inodes (-I 256 or larger) and there are not currently any EAs
359  * consuming all of the available space. For new inodes we always reserve
360  * enough space for the kernel's known extended fields, but for inodes
361  * created with an old kernel this might not have been the case. None of
362  * the extended inode fields is critical for correct filesystem operation.
363  * This macro checks if a certain field fits in the inode. Note that
364  * inode-size = GOOD_OLD_INODE_SIZE + i_extra_isize
365  */
366 #define EXT4_FITS_IN_INODE(ext4_inode, field)           \
367         ((offsetof(typeof(*ext4_inode), field) +        \
368           sizeof((ext4_inode)->field))                  \
369          <= ((size_t) EXT2_GOOD_OLD_INODE_SIZE +                \
370             (ext4_inode)->i_extra_isize))               \
371
372 static inline __u32 ext4_encode_extra_time(const struct timespec *time)
373 {
374         __u32 extra = sizeof(time->tv_sec) > 4 ?
375                         ((time->tv_sec - (__s32)time->tv_sec) >> 32) &
376                         EXT4_EPOCH_MASK : 0;
377         return extra | (time->tv_nsec << EXT4_EPOCH_BITS);
378 }
379
380 static inline void ext4_decode_extra_time(struct timespec *time, __u32 extra)
381 {
382         if (sizeof(time->tv_sec) > 4 && (extra & EXT4_EPOCH_MASK)) {
383                 __u64 extra_bits = extra & EXT4_EPOCH_MASK;
384                 /*
385                  * Prior to kernel 3.14?, we had a broken decode function,
386                  * wherein we effectively did this:
387                  * if (extra_bits == 3)
388                  *     extra_bits = 0;
389                  */
390                 time->tv_sec += extra_bits << 32;
391         }
392         time->tv_nsec = ((extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
393 }
394
395 #define EXT4_INODE_SET_XTIME(xtime, timespec, raw_inode)                       \
396 do {                                                                           \
397         (raw_inode)->xtime = (timespec)->tv_sec;                               \
398         if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra))                    \
399                 (raw_inode)->xtime ## _extra =                                 \
400                                 ext4_encode_extra_time(timespec);              \
401 } while (0)
402
403 #define EXT4_EINODE_SET_XTIME(xtime, timespec, raw_inode)                      \
404 do {                                                                           \
405         if (EXT4_FITS_IN_INODE(raw_inode, xtime))                              \
406                 (raw_inode)->xtime = (timespec)->tv_sec;                       \
407         if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra))                    \
408                 (raw_inode)->xtime ## _extra =                                 \
409                                 ext4_encode_extra_time(timespec);              \
410 } while (0)
411
412 #define EXT4_INODE_GET_XTIME(xtime, timespec, raw_inode)                       \
413 do {                                                                           \
414         (timespec)->tv_sec = (signed)((raw_inode)->xtime);                     \
415         if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra))                    \
416                 ext4_decode_extra_time((timespec),                             \
417                                        (raw_inode)->xtime ## _extra);          \
418         else                                                                   \
419                 (timespec)->tv_nsec = 0;                                       \
420 } while (0)
421
422 #define EXT4_EINODE_GET_XTIME(xtime, timespec, raw_inode)                      \
423 do {                                                                           \
424         if (EXT4_FITS_IN_INODE(raw_inode, xtime))                              \
425                 (timespec)->tv_sec =                                           \
426                         (signed)((raw_inode)->xtime);                          \
427         if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra))                    \
428                 ext4_decode_extra_time((timespec),                             \
429                                        raw_inode->xtime ## _extra);            \
430         else                                                                   \
431                 (timespec)->tv_nsec = 0;                                       \
432 } while (0)
433
434 static void get_now(struct timespec *now)
435 {
436 #ifdef CLOCK_REALTIME
437         if (!clock_gettime(CLOCK_REALTIME, now))
438                 return;
439 #endif
440
441         now->tv_sec = time(NULL);
442         now->tv_nsec = 0;
443 }
444
445 static void increment_version(struct ext2_inode_large *inode)
446 {
447         __u64 ver;
448
449         ver = inode->osd1.linux1.l_i_version;
450         if (EXT4_FITS_IN_INODE(inode, i_version_hi))
451                 ver |= (__u64)inode->i_version_hi << 32;
452         ver++;
453         inode->osd1.linux1.l_i_version = ver;
454         if (EXT4_FITS_IN_INODE(inode, i_version_hi))
455                 inode->i_version_hi = ver >> 32;
456 }
457
458 static void init_times(struct ext2_inode_large *inode)
459 {
460         struct timespec now;
461
462         get_now(&now);
463         EXT4_INODE_SET_XTIME(i_atime, &now, inode);
464         EXT4_INODE_SET_XTIME(i_ctime, &now, inode);
465         EXT4_INODE_SET_XTIME(i_mtime, &now, inode);
466         EXT4_EINODE_SET_XTIME(i_crtime, &now, inode);
467         increment_version(inode);
468 }
469
470 static int update_ctime(ext2_filsys fs, ext2_ino_t ino,
471                         struct ext2_inode_large *pinode)
472 {
473         errcode_t err;
474         struct timespec now;
475         struct ext2_inode_large inode;
476
477         get_now(&now);
478
479         /* If user already has a inode buffer, just update that */
480         if (pinode) {
481                 increment_version(pinode);
482                 EXT4_INODE_SET_XTIME(i_ctime, &now, pinode);
483                 return 0;
484         }
485
486         /* Otherwise we have to read-modify-write the inode */
487         memset(&inode, 0, sizeof(inode));
488         err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
489                                      sizeof(inode));
490         if (err)
491                 return translate_error(fs, ino, err);
492
493         increment_version(&inode);
494         EXT4_INODE_SET_XTIME(i_ctime, &now, &inode);
495
496         err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
497                                       sizeof(inode));
498         if (err)
499                 return translate_error(fs, ino, err);
500
501         return 0;
502 }
503
504 static int update_atime(ext2_filsys fs, ext2_ino_t ino)
505 {
506         errcode_t err;
507         struct ext2_inode_large inode, *pinode;
508         struct timespec atime, mtime, now;
509
510         if (!(fs->flags & EXT2_FLAG_RW))
511                 return 0;
512         memset(&inode, 0, sizeof(inode));
513         err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
514                                      sizeof(inode));
515         if (err)
516                 return translate_error(fs, ino, err);
517
518         pinode = &inode;
519         EXT4_INODE_GET_XTIME(i_atime, &atime, pinode);
520         EXT4_INODE_GET_XTIME(i_mtime, &mtime, pinode);
521         get_now(&now);
522         /*
523          * If atime is newer than mtime and atime hasn't been updated in thirty
524          * seconds, skip the atime update.  Same idea as Linux "relatime".
525          */
526         if (atime.tv_sec >= mtime.tv_sec && atime.tv_sec >= now.tv_sec - 30)
527                 return 0;
528         EXT4_INODE_SET_XTIME(i_atime, &now, &inode);
529
530         err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
531                                       sizeof(inode));
532         if (err)
533                 return translate_error(fs, ino, err);
534
535         return 0;
536 }
537
538 static int update_mtime(ext2_filsys fs, ext2_ino_t ino,
539                         struct ext2_inode_large *pinode)
540 {
541         errcode_t err;
542         struct ext2_inode_large inode;
543         struct timespec now;
544
545         if (pinode) {
546                 get_now(&now);
547                 EXT4_INODE_SET_XTIME(i_mtime, &now, pinode);
548                 EXT4_INODE_SET_XTIME(i_ctime, &now, pinode);
549                 increment_version(pinode);
550                 return 0;
551         }
552
553         memset(&inode, 0, sizeof(inode));
554         err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
555                                      sizeof(inode));
556         if (err)
557                 return translate_error(fs, ino, err);
558
559         get_now(&now);
560         EXT4_INODE_SET_XTIME(i_mtime, &now, &inode);
561         EXT4_INODE_SET_XTIME(i_ctime, &now, &inode);
562         increment_version(&inode);
563
564         err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
565                                       sizeof(inode));
566         if (err)
567                 return translate_error(fs, ino, err);
568
569         return 0;
570 }
571
572 static int ext2_file_type(unsigned int mode)
573 {
574         if (LINUX_S_ISREG(mode))
575                 return EXT2_FT_REG_FILE;
576
577         if (LINUX_S_ISDIR(mode))
578                 return EXT2_FT_DIR;
579
580         if (LINUX_S_ISCHR(mode))
581                 return EXT2_FT_CHRDEV;
582
583         if (LINUX_S_ISBLK(mode))
584                 return EXT2_FT_BLKDEV;
585
586         if (LINUX_S_ISLNK(mode))
587                 return EXT2_FT_SYMLINK;
588
589         if (LINUX_S_ISFIFO(mode))
590                 return EXT2_FT_FIFO;
591
592         if (LINUX_S_ISSOCK(mode))
593                 return EXT2_FT_SOCK;
594
595         return 0;
596 }
597
598 static int fs_can_allocate(struct fuse2fs *ff, blk64_t num)
599 {
600         ext2_filsys fs = ff->fs;
601         blk64_t reserved;
602
603         dbg_printf("%s: Asking for %llu; alloc_all=%d total=%llu free=%llu "
604                    "rsvd=%llu\n", __func__, num, ff->alloc_all_blocks,
605                    ext2fs_blocks_count(fs->super),
606                    ext2fs_free_blocks_count(fs->super),
607                    ext2fs_r_blocks_count(fs->super));
608         if (num > ext2fs_blocks_count(fs->super))
609                 return 0;
610
611         if (ff->alloc_all_blocks)
612                 return 1;
613
614         /*
615          * Different meaning for r_blocks -- libext2fs has bugs where the FS
616          * can get corrupted if it totally runs out of blocks.  Avoid this
617          * by refusing to allocate any of the reserve blocks to anybody.
618          */
619         reserved = ext2fs_r_blocks_count(fs->super);
620         if (reserved == 0)
621                 reserved = ext2fs_blocks_count(fs->super) / 10;
622         return ext2fs_free_blocks_count(fs->super) > reserved + num;
623 }
624
625 static int fs_writeable(ext2_filsys fs)
626 {
627         return (fs->flags & EXT2_FLAG_RW) && (fs->super->s_error_count == 0);
628 }
629
630 static int check_inum_access(ext2_filsys fs, ext2_ino_t ino, mode_t mask)
631 {
632         struct fuse_context *ctxt = fuse_get_context();
633         struct ext2_inode inode;
634         mode_t perms;
635         errcode_t err;
636
637         /* no writing to read-only or broken fs */
638         if ((mask & W_OK) && !fs_writeable(fs))
639                 return -EROFS;
640
641         err = ext2fs_read_inode(fs, ino, &inode);
642         if (err)
643                 return translate_error(fs, ino, err);
644         perms = inode.i_mode & 0777;
645
646         dbg_printf("access ino=%d mask=e%s%s%s perms=0%o fuid=%d fgid=%d "
647                    "uid=%d gid=%d\n", ino,
648                    (mask & R_OK ? "r" : ""), (mask & W_OK ? "w" : ""),
649                    (mask & X_OK ? "x" : ""), perms, inode.i_uid, inode.i_gid,
650                    ctxt->uid, ctxt->gid);
651
652         /* existence check */
653         if (mask == 0)
654                 return 0;
655
656         /* is immutable? */
657         if ((mask & W_OK) &&
658             (inode.i_flags & EXT2_IMMUTABLE_FL))
659                 return -EACCES;
660
661         /* Figure out what root's allowed to do */
662         if (ctxt->uid == 0) {
663                 /* Non-file access always ok */
664                 if (!LINUX_S_ISREG(inode.i_mode))
665                         return 0;
666
667                 /* R/W access to a file always ok */
668                 if (!(mask & X_OK))
669                         return 0;
670
671                 /* X access to a file ok if a user/group/other can X */
672                 if (perms & 0111)
673                         return 0;
674
675                 /* Trying to execute a file that's not executable. BZZT! */
676                 return -EACCES;
677         }
678
679         /* allow owner, if perms match */
680         if (inode.i_uid == ctxt->uid) {
681                 if ((mask & (perms >> 6)) == mask)
682                         return 0;
683                 return -EACCES;
684         }
685
686         /* allow group, if perms match */
687         if (inode.i_gid == ctxt->gid) {
688                 if ((mask & (perms >> 3)) == mask)
689                         return 0;
690                 return -EACCES;
691         }
692
693         /* otherwise check other */
694         if ((mask & perms) == mask)
695                 return 0;
696         return -EACCES;
697 }
698
699 static void op_destroy(void *p EXT2FS_ATTR((unused)))
700 {
701         struct fuse_context *ctxt = fuse_get_context();
702         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
703         ext2_filsys fs;
704         errcode_t err;
705
706         if (ff->magic != FUSE2FS_MAGIC) {
707                 translate_error(global_fs, 0, EXT2_ET_BAD_MAGIC);
708                 return;
709         }
710         fs = ff->fs;
711         dbg_printf("%s: dev=%s\n", __func__, fs->device_name);
712         if (fs->flags & EXT2_FLAG_RW) {
713                 fs->super->s_state |= EXT2_VALID_FS;
714                 if (fs->super->s_error_count)
715                         fs->super->s_state |= EXT2_ERROR_FS;
716                 ext2fs_mark_super_dirty(fs);
717                 err = ext2fs_set_gdt_csum(fs);
718                 if (err)
719                         translate_error(fs, 0, err);
720
721                 err = ext2fs_flush2(fs, 0);
722                 if (err)
723                         translate_error(fs, 0, err);
724         }
725 }
726
727 static void *op_init(struct fuse_conn_info *conn)
728 {
729         struct fuse_context *ctxt = fuse_get_context();
730         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
731         ext2_filsys fs;
732         errcode_t err;
733
734         if (ff->magic != FUSE2FS_MAGIC) {
735                 translate_error(global_fs, 0, EXT2_ET_BAD_MAGIC);
736                 return NULL;
737         }
738         fs = ff->fs;
739         dbg_printf("%s: dev=%s\n", __func__, fs->device_name);
740 #ifdef FUSE_CAP_IOCTL_DIR
741         conn->want |= FUSE_CAP_IOCTL_DIR;
742 #endif
743         if (fs->flags & EXT2_FLAG_RW) {
744                 fs->super->s_mnt_count++;
745                 fs->super->s_mtime = time(NULL);
746                 fs->super->s_state &= ~EXT2_VALID_FS;
747                 ext2fs_mark_super_dirty(fs);
748                 err = ext2fs_flush2(fs, 0);
749                 if (err)
750                         translate_error(fs, 0, err);
751         }
752         return ff;
753 }
754
755 static blkcnt_t blocks_from_inode(ext2_filsys fs,
756                                   struct ext2_inode_large *inode)
757 {
758         blkcnt_t b;
759
760         b = inode->i_blocks;
761         if (ext2fs_has_feature_huge_file(fs->super))
762                 b += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32;
763
764         if (!ext2fs_has_feature_huge_file(fs->super) ||
765             !(inode->i_flags & EXT4_HUGE_FILE_FL))
766                 b *= fs->blocksize / 512;
767         b *= EXT2FS_CLUSTER_RATIO(fs);
768
769         return b;
770 }
771
772 static int stat_inode(ext2_filsys fs, ext2_ino_t ino, struct stat *statbuf)
773 {
774         struct ext2_inode_large inode;
775         dev_t fakedev = 0;
776         errcode_t err;
777         int ret = 0;
778         struct timespec tv;
779
780         memset(&inode, 0, sizeof(inode));
781         err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
782                                      sizeof(inode));
783         if (err)
784                 return translate_error(fs, ino, err);
785
786         memcpy(&fakedev, fs->super->s_uuid, sizeof(fakedev));
787         statbuf->st_dev = fakedev;
788         statbuf->st_ino = ino;
789         statbuf->st_mode = inode.i_mode;
790         statbuf->st_nlink = inode.i_links_count;
791         statbuf->st_uid = inode.i_uid;
792         statbuf->st_gid = inode.i_gid;
793         statbuf->st_size = EXT2_I_SIZE(&inode);
794         statbuf->st_blksize = fs->blocksize;
795         statbuf->st_blocks = blocks_from_inode(fs, &inode);
796         EXT4_INODE_GET_XTIME(i_atime, &tv, &inode);
797         statbuf->st_atime = tv.tv_sec;
798         EXT4_INODE_GET_XTIME(i_mtime, &tv, &inode);
799         statbuf->st_mtime = tv.tv_sec;
800         EXT4_INODE_GET_XTIME(i_ctime, &tv, &inode);
801         statbuf->st_ctime = tv.tv_sec;
802         if (LINUX_S_ISCHR(inode.i_mode) ||
803             LINUX_S_ISBLK(inode.i_mode)) {
804                 if (inode.i_block[0])
805                         statbuf->st_rdev = inode.i_block[0];
806                 else
807                         statbuf->st_rdev = inode.i_block[1];
808         }
809
810         return ret;
811 }
812
813 static int op_getattr(const char *path, struct stat *statbuf)
814 {
815         struct fuse_context *ctxt = fuse_get_context();
816         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
817         ext2_filsys fs;
818         ext2_ino_t ino;
819         errcode_t err;
820         int ret = 0;
821
822         FUSE2FS_CHECK_CONTEXT(ff);
823         fs = ff->fs;
824         dbg_printf("%s: path=%s\n", __func__, path);
825         pthread_mutex_lock(&ff->bfl);
826         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
827         if (err) {
828                 ret = translate_error(fs, 0, err);
829                 goto out;
830         }
831         ret = stat_inode(fs, ino, statbuf);
832 out:
833         pthread_mutex_unlock(&ff->bfl);
834         return ret;
835 }
836
837 static int op_readlink(const char *path, char *buf, size_t len)
838 {
839         struct fuse_context *ctxt = fuse_get_context();
840         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
841         ext2_filsys fs;
842         errcode_t err;
843         ext2_ino_t ino;
844         struct ext2_inode inode;
845         unsigned int got;
846         ext2_file_t file;
847         int ret = 0;
848
849         FUSE2FS_CHECK_CONTEXT(ff);
850         fs = ff->fs;
851         dbg_printf("%s: path=%s\n", __func__, path);
852         pthread_mutex_lock(&ff->bfl);
853         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
854         if (err || ino == 0) {
855                 ret = translate_error(fs, 0, err);
856                 goto out;
857         }
858
859         err = ext2fs_read_inode(fs, ino, &inode);
860         if (err) {
861                 ret = translate_error(fs, ino, err);
862                 goto out;
863         }
864
865         if (!LINUX_S_ISLNK(inode.i_mode)) {
866                 ret = -EINVAL;
867                 goto out;
868         }
869
870         len--;
871         if (inode.i_size < len)
872                 len = inode.i_size;
873         if (ext2fs_is_fast_symlink(&inode))
874                 memcpy(buf, (char *)inode.i_block, len);
875         else {
876                 /* big/inline symlink */
877
878                 err = ext2fs_file_open(fs, ino, 0, &file);
879                 if (err) {
880                         ret = translate_error(fs, ino, err);
881                         goto out;
882                 }
883
884                 err = ext2fs_file_read(file, buf, len, &got);
885                 if (err || got != len) {
886                         ext2fs_file_close(file);
887                         ret = translate_error(fs, ino, err);
888                         goto out2;
889                 }
890
891 out2:
892                 err = ext2fs_file_close(file);
893                 if (ret)
894                         goto out;
895                 if (err) {
896                         ret = translate_error(fs, ino, err);
897                         goto out;
898                 }
899         }
900         buf[len] = 0;
901
902         if (fs_writeable(fs)) {
903                 ret = update_atime(fs, ino);
904                 if (ret)
905                         goto out;
906         }
907
908 out:
909         pthread_mutex_unlock(&ff->bfl);
910         return ret;
911 }
912
913 static int op_mknod(const char *path, mode_t mode, dev_t dev)
914 {
915         struct fuse_context *ctxt = fuse_get_context();
916         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
917         ext2_filsys fs;
918         ext2_ino_t parent, child;
919         char *temp_path;
920         errcode_t err;
921         char *node_name, a;
922         int filetype;
923         struct ext2_inode_large inode;
924         int ret = 0;
925
926         FUSE2FS_CHECK_CONTEXT(ff);
927         fs = ff->fs;
928         dbg_printf("%s: path=%s mode=0%o dev=0x%x\n", __func__, path, mode,
929                    (unsigned int)dev);
930         temp_path = strdup(path);
931         if (!temp_path) {
932                 ret = -ENOMEM;
933                 goto out;
934         }
935         node_name = strrchr(temp_path, '/');
936         if (!node_name) {
937                 ret = -ENOMEM;
938                 goto out;
939         }
940         node_name++;
941         a = *node_name;
942         *node_name = 0;
943
944         pthread_mutex_lock(&ff->bfl);
945         if (!fs_can_allocate(ff, 2)) {
946                 ret = -ENOSPC;
947                 goto out2;
948         }
949
950         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
951                            &parent);
952         if (err) {
953                 ret = translate_error(fs, 0, err);
954                 goto out2;
955         }
956
957         ret = check_inum_access(fs, parent, W_OK);
958         if (ret)
959                 goto out2;
960
961         *node_name = a;
962
963         if (LINUX_S_ISCHR(mode))
964                 filetype = EXT2_FT_CHRDEV;
965         else if (LINUX_S_ISBLK(mode))
966                 filetype = EXT2_FT_BLKDEV;
967         else if (LINUX_S_ISFIFO(mode))
968                 filetype = EXT2_FT_FIFO;
969         else if (LINUX_S_ISSOCK(mode))
970                 filetype = EXT2_FT_SOCK;
971         else {
972                 ret = -EINVAL;
973                 goto out2;
974         }
975
976         err = ext2fs_new_inode(fs, parent, mode, 0, &child);
977         if (err) {
978                 ret = translate_error(fs, 0, err);
979                 goto out2;
980         }
981
982         dbg_printf("%s: create ino=%d/name=%s in dir=%d\n", __func__, child,
983                    node_name, parent);
984         err = ext2fs_link(fs, parent, node_name, child, filetype);
985         if (err == EXT2_ET_DIR_NO_SPACE) {
986                 err = ext2fs_expand_dir(fs, parent);
987                 if (err) {
988                         ret = translate_error(fs, parent, err);
989                         goto out2;
990                 }
991
992                 err = ext2fs_link(fs, parent, node_name, child,
993                                      filetype);
994         }
995         if (err) {
996                 ret = translate_error(fs, parent, err);
997                 goto out2;
998         }
999
1000         ret = update_mtime(fs, parent, NULL);
1001         if (ret)
1002                 goto out2;
1003
1004         memset(&inode, 0, sizeof(inode));
1005         inode.i_mode = mode;
1006
1007         if (dev & ~0xFFFF)
1008                 inode.i_block[1] = dev;
1009         else
1010                 inode.i_block[0] = dev;
1011         inode.i_links_count = 1;
1012         inode.i_extra_isize = sizeof(struct ext2_inode_large) -
1013                 EXT2_GOOD_OLD_INODE_SIZE;
1014         inode.i_uid = ctxt->uid;
1015         inode.i_gid = ctxt->gid;
1016
1017         err = ext2fs_write_new_inode(fs, child, (struct ext2_inode *)&inode);
1018         if (err) {
1019                 ret = translate_error(fs, child, err);
1020                 goto out2;
1021         }
1022
1023         inode.i_generation = ff->next_generation++;
1024         init_times(&inode);
1025         err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode,
1026                                       sizeof(inode));
1027         if (err) {
1028                 ret = translate_error(fs, child, err);
1029                 goto out2;
1030         }
1031
1032         ext2fs_inode_alloc_stats2(fs, child, 1, 0);
1033
1034 out2:
1035         pthread_mutex_unlock(&ff->bfl);
1036 out:
1037         free(temp_path);
1038         return ret;
1039 }
1040
1041 static int op_mkdir(const char *path, mode_t mode)
1042 {
1043         struct fuse_context *ctxt = fuse_get_context();
1044         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1045         ext2_filsys fs;
1046         ext2_ino_t parent, child;
1047         char *temp_path;
1048         errcode_t err;
1049         char *node_name, a;
1050         struct ext2_inode_large inode;
1051         char *block;
1052         blk64_t blk;
1053         int ret = 0;
1054         mode_t parent_sgid;
1055
1056         FUSE2FS_CHECK_CONTEXT(ff);
1057         fs = ff->fs;
1058         dbg_printf("%s: path=%s mode=0%o\n", __func__, path, mode);
1059         temp_path = strdup(path);
1060         if (!temp_path) {
1061                 ret = -ENOMEM;
1062                 goto out;
1063         }
1064         node_name = strrchr(temp_path, '/');
1065         if (!node_name) {
1066                 ret = -ENOMEM;
1067                 goto out;
1068         }
1069         node_name++;
1070         a = *node_name;
1071         *node_name = 0;
1072
1073         pthread_mutex_lock(&ff->bfl);
1074         if (!fs_can_allocate(ff, 1)) {
1075                 ret = -ENOSPC;
1076                 goto out2;
1077         }
1078
1079         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
1080                            &parent);
1081         if (err) {
1082                 ret = translate_error(fs, 0, err);
1083                 goto out2;
1084         }
1085
1086         ret = check_inum_access(fs, parent, W_OK);
1087         if (ret)
1088                 goto out2;
1089
1090         /* Is the parent dir sgid? */
1091         err = ext2fs_read_inode_full(fs, parent, (struct ext2_inode *)&inode,
1092                                      sizeof(inode));
1093         if (err) {
1094                 ret = translate_error(fs, parent, err);
1095                 goto out2;
1096         }
1097         parent_sgid = inode.i_mode & S_ISGID;
1098
1099         *node_name = a;
1100
1101         err = ext2fs_mkdir(fs, parent, 0, node_name);
1102         if (err == EXT2_ET_DIR_NO_SPACE) {
1103                 err = ext2fs_expand_dir(fs, parent);
1104                 if (err) {
1105                         ret = translate_error(fs, parent, err);
1106                         goto out2;
1107                 }
1108
1109                 err = ext2fs_mkdir(fs, parent, 0, node_name);
1110         }
1111         if (err) {
1112                 ret = translate_error(fs, parent, err);
1113                 goto out2;
1114         }
1115
1116         ret = update_mtime(fs, parent, NULL);
1117         if (ret)
1118                 goto out2;
1119
1120         /* Still have to update the uid/gid of the dir */
1121         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
1122                            &child);
1123         if (err) {
1124                 ret = translate_error(fs, 0, err);
1125                 goto out2;
1126         }
1127         dbg_printf("%s: created ino=%d/path=%s in dir=%d\n", __func__, child,
1128                    node_name, parent);
1129
1130         memset(&inode, 0, sizeof(inode));
1131         err = ext2fs_read_inode_full(fs, child, (struct ext2_inode *)&inode,
1132                                      sizeof(inode));
1133         if (err) {
1134                 ret = translate_error(fs, child, err);
1135                 goto out2;
1136         }
1137
1138         inode.i_uid = ctxt->uid;
1139         inode.i_gid = ctxt->gid;
1140         inode.i_mode = LINUX_S_IFDIR | (mode & ~(S_ISUID | fs->umask)) |
1141                        parent_sgid;
1142         inode.i_generation = ff->next_generation++;
1143
1144         err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode,
1145                                       sizeof(inode));
1146         if (err) {
1147                 ret = translate_error(fs, child, err);
1148                 goto out2;
1149         }
1150
1151         /* Rewrite the directory block checksum, having set i_generation */
1152         if ((inode.i_flags & EXT4_INLINE_DATA_FL) ||
1153             !ext2fs_has_feature_metadata_csum(fs->super))
1154                 goto out2;
1155         err = ext2fs_new_dir_block(fs, child, parent, &block);
1156         if (err) {
1157                 ret = translate_error(fs, child, err);
1158                 goto out2;
1159         }
1160         err = ext2fs_bmap2(fs, child, (struct ext2_inode *)&inode, NULL, 0, 0,
1161                            NULL, &blk);
1162         if (err) {
1163                 ret = translate_error(fs, child, err);
1164                 goto out3;
1165         }
1166         err = ext2fs_write_dir_block4(fs, blk, block, 0, child);
1167         if (err) {
1168                 ret = translate_error(fs, child, err);
1169                 goto out3;
1170         }
1171
1172 out3:
1173         ext2fs_free_mem(&block);
1174 out2:
1175         pthread_mutex_unlock(&ff->bfl);
1176 out:
1177         free(temp_path);
1178         return ret;
1179 }
1180
1181 static int unlink_file_by_name(ext2_filsys fs, const char *path)
1182 {
1183         errcode_t err;
1184         ext2_ino_t dir;
1185         char *filename = strdup(path);
1186         char *base_name;
1187         int ret;
1188
1189         base_name = strrchr(filename, '/');
1190         if (base_name) {
1191                 *base_name++ = '\0';
1192                 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, filename,
1193                                    &dir);
1194                 if (err) {
1195                         free(filename);
1196                         return translate_error(fs, 0, err);
1197                 }
1198         } else {
1199                 dir = EXT2_ROOT_INO;
1200                 base_name = filename;
1201         }
1202
1203         ret = check_inum_access(fs, dir, W_OK);
1204         if (ret) {
1205                 free(filename);
1206                 return ret;
1207         }
1208
1209         dbg_printf("%s: unlinking name=%s from dir=%d\n", __func__,
1210                    base_name, dir);
1211         err = ext2fs_unlink(fs, dir, base_name, 0, 0);
1212         free(filename);
1213         if (err)
1214                 return translate_error(fs, dir, err);
1215
1216         return update_mtime(fs, dir, NULL);
1217 }
1218
1219 static int remove_inode(struct fuse2fs *ff, ext2_ino_t ino)
1220 {
1221         ext2_filsys fs = ff->fs;
1222         errcode_t err;
1223         struct ext2_inode_large inode;
1224         int ret = 0;
1225
1226         memset(&inode, 0, sizeof(inode));
1227         err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
1228                                      sizeof(inode));
1229         if (err) {
1230                 ret = translate_error(fs, ino, err);
1231                 goto out;
1232         }
1233         dbg_printf("%s: put ino=%d links=%d\n", __func__, ino,
1234                    inode.i_links_count);
1235
1236         switch (inode.i_links_count) {
1237         case 0:
1238                 return 0; /* XXX: already done? */
1239         case 1:
1240                 inode.i_links_count--;
1241                 inode.i_dtime = fs->now ? fs->now : time(0);
1242                 break;
1243         default:
1244                 inode.i_links_count--;
1245         }
1246
1247         ret = update_ctime(fs, ino, &inode);
1248         if (ret)
1249                 goto out;
1250
1251         if (inode.i_links_count)
1252                 goto write_out;
1253
1254         /* Nobody holds this file; free its blocks! */
1255         err = ext2fs_free_ext_attr(fs, ino, &inode);
1256         if (err)
1257                 goto write_out;
1258
1259         if (ext2fs_inode_has_valid_blocks2(fs, (struct ext2_inode *)&inode)) {
1260                 err = ext2fs_punch(fs, ino, (struct ext2_inode *)&inode, NULL,
1261                                    0, ~0ULL);
1262                 if (err) {
1263                         ret = translate_error(fs, ino, err);
1264                         goto write_out;
1265                 }
1266         }
1267
1268         ext2fs_inode_alloc_stats2(fs, ino, -1,
1269                                   LINUX_S_ISDIR(inode.i_mode));
1270
1271 write_out:
1272         err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
1273                                       sizeof(inode));
1274         if (err) {
1275                 ret = translate_error(fs, ino, err);
1276                 goto out;
1277         }
1278 out:
1279         return ret;
1280 }
1281
1282 static int __op_unlink(struct fuse2fs *ff, const char *path)
1283 {
1284         ext2_filsys fs = ff->fs;
1285         ext2_ino_t ino;
1286         errcode_t err;
1287         int ret = 0;
1288
1289         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
1290         if (err) {
1291                 ret = translate_error(fs, 0, err);
1292                 goto out;
1293         }
1294
1295         ret = unlink_file_by_name(fs, path);
1296         if (ret)
1297                 goto out;
1298
1299         ret = remove_inode(ff, ino);
1300         if (ret)
1301                 goto out;
1302 out:
1303         return ret;
1304 }
1305
1306 static int op_unlink(const char *path)
1307 {
1308         struct fuse_context *ctxt = fuse_get_context();
1309         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1310         int ret;
1311
1312         FUSE2FS_CHECK_CONTEXT(ff);
1313         pthread_mutex_lock(&ff->bfl);
1314         ret = __op_unlink(ff, path);
1315         pthread_mutex_unlock(&ff->bfl);
1316         return ret;
1317 }
1318
1319 struct rd_struct {
1320         ext2_ino_t      parent;
1321         int             empty;
1322 };
1323
1324 static int rmdir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
1325                       int       entry EXT2FS_ATTR((unused)),
1326                       struct ext2_dir_entry *dirent,
1327                       int       offset EXT2FS_ATTR((unused)),
1328                       int       blocksize EXT2FS_ATTR((unused)),
1329                       char      *buf EXT2FS_ATTR((unused)),
1330                       void      *private)
1331 {
1332         struct rd_struct *rds = (struct rd_struct *) private;
1333
1334         if (dirent->inode == 0)
1335                 return 0;
1336         if (((dirent->name_len & 0xFF) == 1) && (dirent->name[0] == '.'))
1337                 return 0;
1338         if (((dirent->name_len & 0xFF) == 2) && (dirent->name[0] == '.') &&
1339             (dirent->name[1] == '.')) {
1340                 rds->parent = dirent->inode;
1341                 return 0;
1342         }
1343         rds->empty = 0;
1344         return 0;
1345 }
1346
1347 static int __op_rmdir(struct fuse2fs *ff, const char *path)
1348 {
1349         ext2_filsys fs = ff->fs;
1350         ext2_ino_t child;
1351         errcode_t err;
1352         struct ext2_inode_large inode;
1353         struct rd_struct rds;
1354         int ret = 0;
1355
1356         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &child);
1357         if (err) {
1358                 ret = translate_error(fs, 0, err);
1359                 goto out;
1360         }
1361         dbg_printf("%s: rmdir path=%s ino=%d\n", __func__, path, child);
1362
1363         rds.parent = 0;
1364         rds.empty = 1;
1365
1366         err = ext2fs_dir_iterate2(fs, child, 0, 0, rmdir_proc, &rds);
1367         if (err) {
1368                 ret = translate_error(fs, child, err);
1369                 goto out;
1370         }
1371
1372         if (rds.empty == 0) {
1373                 ret = -ENOTEMPTY;
1374                 goto out;
1375         }
1376
1377         ret = unlink_file_by_name(fs, path);
1378         if (ret)
1379                 goto out;
1380         /* Directories have to be "removed" twice. */
1381         ret = remove_inode(ff, child);
1382         if (ret)
1383                 goto out;
1384         ret = remove_inode(ff, child);
1385         if (ret)
1386                 goto out;
1387
1388         if (rds.parent) {
1389                 dbg_printf("%s: decr dir=%d link count\n", __func__,
1390                            rds.parent);
1391                 err = ext2fs_read_inode_full(fs, rds.parent,
1392                                              (struct ext2_inode *)&inode,
1393                                              sizeof(inode));
1394                 if (err) {
1395                         ret = translate_error(fs, rds.parent, err);
1396                         goto out;
1397                 }
1398                 if (inode.i_links_count > 1)
1399                         inode.i_links_count--;
1400                 ret = update_mtime(fs, rds.parent, &inode);
1401                 if (ret)
1402                         goto out;
1403                 err = ext2fs_write_inode_full(fs, rds.parent,
1404                                               (struct ext2_inode *)&inode,
1405                                               sizeof(inode));
1406                 if (err) {
1407                         ret = translate_error(fs, rds.parent, err);
1408                         goto out;
1409                 }
1410         }
1411
1412 out:
1413         return ret;
1414 }
1415
1416 static int op_rmdir(const char *path)
1417 {
1418         struct fuse_context *ctxt = fuse_get_context();
1419         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1420         int ret;
1421
1422         FUSE2FS_CHECK_CONTEXT(ff);
1423         pthread_mutex_lock(&ff->bfl);
1424         ret = __op_rmdir(ff, path);
1425         pthread_mutex_unlock(&ff->bfl);
1426         return ret;
1427 }
1428
1429 static int op_symlink(const char *src, const char *dest)
1430 {
1431         struct fuse_context *ctxt = fuse_get_context();
1432         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1433         ext2_filsys fs;
1434         ext2_ino_t parent, child;
1435         char *temp_path;
1436         errcode_t err;
1437         char *node_name, a;
1438         struct ext2_inode_large inode;
1439         int ret = 0;
1440
1441         FUSE2FS_CHECK_CONTEXT(ff);
1442         fs = ff->fs;
1443         dbg_printf("%s: symlink %s to %s\n", __func__, src, dest);
1444         temp_path = strdup(dest);
1445         if (!temp_path) {
1446                 ret = -ENOMEM;
1447                 goto out;
1448         }
1449         node_name = strrchr(temp_path, '/');
1450         if (!node_name) {
1451                 ret = -ENOMEM;
1452                 goto out;
1453         }
1454         node_name++;
1455         a = *node_name;
1456         *node_name = 0;
1457
1458         pthread_mutex_lock(&ff->bfl);
1459         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
1460                            &parent);
1461         *node_name = a;
1462         if (err) {
1463                 ret = translate_error(fs, 0, err);
1464                 goto out2;
1465         }
1466
1467         ret = check_inum_access(fs, parent, W_OK);
1468         if (ret)
1469                 goto out2;
1470
1471
1472         /* Create symlink */
1473         err = ext2fs_symlink(fs, parent, 0, node_name, src);
1474         if (err == EXT2_ET_DIR_NO_SPACE) {
1475                 err = ext2fs_expand_dir(fs, parent);
1476                 if (err) {
1477                         ret = translate_error(fs, parent, err);
1478                         goto out2;
1479                 }
1480
1481                 err = ext2fs_symlink(fs, parent, 0, node_name, src);
1482         }
1483         if (err) {
1484                 ret = translate_error(fs, parent, err);
1485                 goto out2;
1486         }
1487
1488         /* Update parent dir's mtime */
1489         ret = update_mtime(fs, parent, NULL);
1490         if (ret)
1491                 goto out2;
1492
1493         /* Still have to update the uid/gid of the symlink */
1494         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
1495                            &child);
1496         if (err) {
1497                 ret = translate_error(fs, 0, err);
1498                 goto out2;
1499         }
1500         dbg_printf("%s: symlinking ino=%d/name=%s to dir=%d\n", __func__,
1501                    child, node_name, parent);
1502
1503         memset(&inode, 0, sizeof(inode));
1504         err = ext2fs_read_inode_full(fs, child, (struct ext2_inode *)&inode,
1505                                      sizeof(inode));
1506         if (err) {
1507                 ret = translate_error(fs, child, err);
1508                 goto out2;
1509         }
1510
1511         inode.i_uid = ctxt->uid;
1512         inode.i_gid = ctxt->gid;
1513         inode.i_generation = ff->next_generation++;
1514
1515         err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode,
1516                                       sizeof(inode));
1517         if (err) {
1518                 ret = translate_error(fs, child, err);
1519                 goto out2;
1520         }
1521 out2:
1522         pthread_mutex_unlock(&ff->bfl);
1523 out:
1524         free(temp_path);
1525         return ret;
1526 }
1527
1528 struct update_dotdot {
1529         ext2_ino_t new_dotdot;
1530 };
1531
1532 static int update_dotdot_helper(ext2_ino_t dir EXT2FS_ATTR((unused)),
1533                                 int entry EXT2FS_ATTR((unused)),
1534                                 struct ext2_dir_entry *dirent,
1535                                 int offset EXT2FS_ATTR((unused)),
1536                                 int blocksize EXT2FS_ATTR((unused)),
1537                                 char *buf EXT2FS_ATTR((unused)),
1538                                 void *priv_data)
1539 {
1540         struct update_dotdot *ud = priv_data;
1541
1542         if (ext2fs_dirent_name_len(dirent) == 2 &&
1543             dirent->name[0] == '.' && dirent->name[1] == '.') {
1544                 dirent->inode = ud->new_dotdot;
1545                 return DIRENT_CHANGED | DIRENT_ABORT;
1546         }
1547
1548         return 0;
1549 }
1550
1551 static int op_rename(const char *from, const char *to)
1552 {
1553         struct fuse_context *ctxt = fuse_get_context();
1554         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1555         ext2_filsys fs;
1556         errcode_t err;
1557         ext2_ino_t from_ino, to_ino, to_dir_ino, from_dir_ino;
1558         char *temp_to = NULL, *temp_from = NULL;
1559         char *cp, a;
1560         struct ext2_inode inode;
1561         struct update_dotdot ud;
1562         int ret = 0;
1563
1564         FUSE2FS_CHECK_CONTEXT(ff);
1565         fs = ff->fs;
1566         dbg_printf("%s: renaming %s to %s\n", __func__, from, to);
1567         pthread_mutex_lock(&ff->bfl);
1568         if (!fs_can_allocate(ff, 5)) {
1569                 ret = -ENOSPC;
1570                 goto out;
1571         }
1572
1573         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, from, &from_ino);
1574         if (err || from_ino == 0) {
1575                 ret = translate_error(fs, 0, err);
1576                 goto out;
1577         }
1578
1579         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, to, &to_ino);
1580         if (err && err != EXT2_ET_FILE_NOT_FOUND) {
1581                 ret = translate_error(fs, 0, err);
1582                 goto out;
1583         }
1584
1585         if (err == EXT2_ET_FILE_NOT_FOUND)
1586                 to_ino = 0;
1587
1588         /* Already the same file? */
1589         if (to_ino != 0 && to_ino == from_ino) {
1590                 ret = 0;
1591                 goto out;
1592         }
1593
1594         temp_to = strdup(to);
1595         if (!temp_to) {
1596                 ret = -ENOMEM;
1597                 goto out;
1598         }
1599
1600         temp_from = strdup(from);
1601         if (!temp_from) {
1602                 ret = -ENOMEM;
1603                 goto out2;
1604         }
1605
1606         /* Find parent dir of the source and check write access */
1607         cp = strrchr(temp_from, '/');
1608         if (!cp) {
1609                 ret = -EINVAL;
1610                 goto out2;
1611         }
1612
1613         a = *(cp + 1);
1614         *(cp + 1) = 0;
1615         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_from,
1616                            &from_dir_ino);
1617         *(cp + 1) = a;
1618         if (err) {
1619                 ret = translate_error(fs, 0, err);
1620                 goto out2;
1621         }
1622         if (from_dir_ino == 0) {
1623                 ret = -ENOENT;
1624                 goto out2;
1625         }
1626
1627         ret = check_inum_access(fs, from_dir_ino, W_OK);
1628         if (ret)
1629                 goto out2;
1630
1631         /* Find parent dir of the destination and check write access */
1632         cp = strrchr(temp_to, '/');
1633         if (!cp) {
1634                 ret = -EINVAL;
1635                 goto out2;
1636         }
1637
1638         a = *(cp + 1);
1639         *(cp + 1) = 0;
1640         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_to,
1641                            &to_dir_ino);
1642         *(cp + 1) = a;
1643         if (err) {
1644                 ret = translate_error(fs, 0, err);
1645                 goto out2;
1646         }
1647         if (to_dir_ino == 0) {
1648                 ret = -ENOENT;
1649                 goto out2;
1650         }
1651
1652         ret = check_inum_access(fs, to_dir_ino, W_OK);
1653         if (ret)
1654                 goto out2;
1655
1656         /* If the target exists, unlink it first */
1657         if (to_ino != 0) {
1658                 err = ext2fs_read_inode(fs, to_ino, &inode);
1659                 if (err) {
1660                         ret = translate_error(fs, to_ino, err);
1661                         goto out2;
1662                 }
1663
1664                 dbg_printf("%s: unlinking %s ino=%d\n", __func__,
1665                            LINUX_S_ISDIR(inode.i_mode) ? "dir" : "file",
1666                            to_ino);
1667                 if (LINUX_S_ISDIR(inode.i_mode))
1668                         ret = __op_rmdir(ff, to);
1669                 else
1670                         ret = __op_unlink(ff, to);
1671                 if (ret)
1672                         goto out2;
1673         }
1674
1675         /* Get ready to do the move */
1676         err = ext2fs_read_inode(fs, from_ino, &inode);
1677         if (err) {
1678                 ret = translate_error(fs, from_ino, err);
1679                 goto out2;
1680         }
1681
1682         /* Link in the new file */
1683         dbg_printf("%s: linking ino=%d/path=%s to dir=%d\n", __func__,
1684                    from_ino, cp + 1, to_dir_ino);
1685         err = ext2fs_link(fs, to_dir_ino, cp + 1, from_ino,
1686                           ext2_file_type(inode.i_mode));
1687         if (err == EXT2_ET_DIR_NO_SPACE) {
1688                 err = ext2fs_expand_dir(fs, to_dir_ino);
1689                 if (err) {
1690                         ret = translate_error(fs, to_dir_ino, err);
1691                         goto out2;
1692                 }
1693
1694                 err = ext2fs_link(fs, to_dir_ino, cp + 1, from_ino,
1695                                      ext2_file_type(inode.i_mode));
1696         }
1697         if (err) {
1698                 ret = translate_error(fs, to_dir_ino, err);
1699                 goto out2;
1700         }
1701
1702         /* Update '..' pointer if dir */
1703         err = ext2fs_read_inode(fs, from_ino, &inode);
1704         if (err) {
1705                 ret = translate_error(fs, from_ino, err);
1706                 goto out2;
1707         }
1708
1709         if (LINUX_S_ISDIR(inode.i_mode)) {
1710                 ud.new_dotdot = to_dir_ino;
1711                 dbg_printf("%s: updating .. entry for dir=%d\n", __func__,
1712                            to_dir_ino);
1713                 err = ext2fs_dir_iterate2(fs, from_ino, 0, NULL,
1714                                           update_dotdot_helper, &ud);
1715                 if (err) {
1716                         ret = translate_error(fs, from_ino, err);
1717                         goto out2;
1718                 }
1719
1720                 /* Decrease from_dir_ino's links_count */
1721                 dbg_printf("%s: moving linkcount from dir=%d to dir=%d\n",
1722                            __func__, from_dir_ino, to_dir_ino);
1723                 err = ext2fs_read_inode(fs, from_dir_ino, &inode);
1724                 if (err) {
1725                         ret = translate_error(fs, from_dir_ino, err);
1726                         goto out2;
1727                 }
1728                 inode.i_links_count--;
1729                 err = ext2fs_write_inode(fs, from_dir_ino, &inode);
1730                 if (err) {
1731                         ret = translate_error(fs, from_dir_ino, err);
1732                         goto out2;
1733                 }
1734
1735                 /* Increase to_dir_ino's links_count */
1736                 err = ext2fs_read_inode(fs, to_dir_ino, &inode);
1737                 if (err) {
1738                         ret = translate_error(fs, to_dir_ino, err);
1739                         goto out2;
1740                 }
1741                 inode.i_links_count++;
1742                 err = ext2fs_write_inode(fs, to_dir_ino, &inode);
1743                 if (err) {
1744                         ret = translate_error(fs, to_dir_ino, err);
1745                         goto out2;
1746                 }
1747         }
1748
1749         /* Update timestamps */
1750         ret = update_ctime(fs, from_ino, NULL);
1751         if (ret)
1752                 goto out2;
1753
1754         ret = update_mtime(fs, to_dir_ino, NULL);
1755         if (ret)
1756                 goto out2;
1757
1758         /* Remove the old file */
1759         ret = unlink_file_by_name(fs, from);
1760         if (ret)
1761                 goto out2;
1762
1763         /* Flush the whole mess out */
1764         err = ext2fs_flush2(fs, 0);
1765         if (err)
1766                 ret = translate_error(fs, 0, err);
1767
1768 out2:
1769         free(temp_from);
1770         free(temp_to);
1771 out:
1772         pthread_mutex_unlock(&ff->bfl);
1773         return ret;
1774 }
1775
1776 static int op_link(const char *src, const char *dest)
1777 {
1778         struct fuse_context *ctxt = fuse_get_context();
1779         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1780         ext2_filsys fs;
1781         char *temp_path;
1782         errcode_t err;
1783         char *node_name, a;
1784         ext2_ino_t parent, ino;
1785         struct ext2_inode_large inode;
1786         int ret = 0;
1787
1788         FUSE2FS_CHECK_CONTEXT(ff);
1789         fs = ff->fs;
1790         dbg_printf("%s: src=%s dest=%s\n", __func__, src, dest);
1791         temp_path = strdup(dest);
1792         if (!temp_path) {
1793                 ret = -ENOMEM;
1794                 goto out;
1795         }
1796         node_name = strrchr(temp_path, '/');
1797         if (!node_name) {
1798                 ret = -ENOMEM;
1799                 goto out;
1800         }
1801         node_name++;
1802         a = *node_name;
1803         *node_name = 0;
1804
1805         pthread_mutex_lock(&ff->bfl);
1806         if (!fs_can_allocate(ff, 2)) {
1807                 ret = -ENOSPC;
1808                 goto out2;
1809         }
1810
1811         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
1812                            &parent);
1813         *node_name = a;
1814         if (err) {
1815                 err = -ENOENT;
1816                 goto out2;
1817         }
1818
1819         ret = check_inum_access(fs, parent, W_OK);
1820         if (ret)
1821                 goto out2;
1822
1823
1824         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, src, &ino);
1825         if (err || ino == 0) {
1826                 ret = translate_error(fs, 0, err);
1827                 goto out2;
1828         }
1829
1830         memset(&inode, 0, sizeof(inode));
1831         err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
1832                                      sizeof(inode));
1833         if (err) {
1834                 ret = translate_error(fs, ino, err);
1835                 goto out2;
1836         }
1837
1838         inode.i_links_count++;
1839         ret = update_ctime(fs, ino, &inode);
1840         if (ret)
1841                 goto out2;
1842
1843         err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
1844                                       sizeof(inode));
1845         if (err) {
1846                 ret = translate_error(fs, ino, err);
1847                 goto out2;
1848         }
1849
1850         dbg_printf("%s: linking ino=%d/name=%s to dir=%d\n", __func__, ino,
1851                    node_name, parent);
1852         err = ext2fs_link(fs, parent, node_name, ino,
1853                           ext2_file_type(inode.i_mode));
1854         if (err == EXT2_ET_DIR_NO_SPACE) {
1855                 err = ext2fs_expand_dir(fs, parent);
1856                 if (err) {
1857                         ret = translate_error(fs, parent, err);
1858                         goto out2;
1859                 }
1860
1861                 err = ext2fs_link(fs, parent, node_name, ino,
1862                                      ext2_file_type(inode.i_mode));
1863         }
1864         if (err) {
1865                 ret = translate_error(fs, parent, err);
1866                 goto out2;
1867         }
1868
1869         ret = update_mtime(fs, parent, NULL);
1870         if (ret)
1871                 goto out2;
1872
1873 out2:
1874         pthread_mutex_unlock(&ff->bfl);
1875 out:
1876         free(temp_path);
1877         return ret;
1878 }
1879
1880 static int op_chmod(const char *path, mode_t mode)
1881 {
1882         struct fuse_context *ctxt = fuse_get_context();
1883         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1884         ext2_filsys fs;
1885         errcode_t err;
1886         ext2_ino_t ino;
1887         struct ext2_inode_large inode;
1888         int ret = 0;
1889
1890         FUSE2FS_CHECK_CONTEXT(ff);
1891         fs = ff->fs;
1892         pthread_mutex_lock(&ff->bfl);
1893         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
1894         if (err) {
1895                 ret = translate_error(fs, 0, err);
1896                 goto out;
1897         }
1898         dbg_printf("%s: path=%s mode=0%o ino=%d\n", __func__, path, mode, ino);
1899
1900         memset(&inode, 0, sizeof(inode));
1901         err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
1902                                      sizeof(inode));
1903         if (err) {
1904                 ret = translate_error(fs, ino, err);
1905                 goto out;
1906         }
1907
1908         if (ctxt->uid != 0 && ctxt->uid != inode.i_uid) {
1909                 ret = -EPERM;
1910                 goto out;
1911         }
1912
1913         /*
1914          * XXX: We should really check that the inode gid is not in /any/
1915          * of the user's groups, but FUSE only tells us about the primary
1916          * group.
1917          */
1918         if (ctxt->uid != 0 && ctxt->gid != inode.i_gid)
1919                 mode &= ~S_ISGID;
1920
1921         inode.i_mode &= ~0xFFF;
1922         inode.i_mode |= mode & 0xFFF;
1923         ret = update_ctime(fs, ino, &inode);
1924         if (ret)
1925                 goto out;
1926
1927         err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
1928                                       sizeof(inode));
1929         if (err) {
1930                 ret = translate_error(fs, ino, err);
1931                 goto out;
1932         }
1933
1934 out:
1935         pthread_mutex_unlock(&ff->bfl);
1936         return ret;
1937 }
1938
1939 static int op_chown(const char *path, uid_t owner, gid_t group)
1940 {
1941         struct fuse_context *ctxt = fuse_get_context();
1942         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1943         ext2_filsys fs;
1944         errcode_t err;
1945         ext2_ino_t ino;
1946         struct ext2_inode_large inode;
1947         int ret = 0;
1948
1949         FUSE2FS_CHECK_CONTEXT(ff);
1950         fs = ff->fs;
1951         pthread_mutex_lock(&ff->bfl);
1952         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
1953         if (err) {
1954                 ret = translate_error(fs, 0, err);
1955                 goto out;
1956         }
1957         dbg_printf("%s: path=%s owner=%d group=%d ino=%d\n", __func__,
1958                    path, owner, group, ino);
1959
1960         memset(&inode, 0, sizeof(inode));
1961         err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
1962                                      sizeof(inode));
1963         if (err) {
1964                 ret = translate_error(fs, ino, err);
1965                 goto out;
1966         }
1967
1968         /* FUSE seems to feed us ~0 to mean "don't change" */
1969         if (owner != (uid_t) ~0) {
1970                 /* Only root gets to change UID. */
1971                 if (ctxt->uid != 0 &&
1972                     !(inode.i_uid == ctxt->uid && owner == ctxt->uid)) {
1973                         ret = -EPERM;
1974                         goto out;
1975                 }
1976                 inode.i_uid = owner;
1977         }
1978
1979         if (group != (gid_t) ~0) {
1980                 /* Only root or the owner get to change GID. */
1981                 if (ctxt->uid != 0 && inode.i_uid != ctxt->uid) {
1982                         ret = -EPERM;
1983                         goto out;
1984                 }
1985
1986                 /* XXX: We /should/ check group membership but FUSE */
1987                 inode.i_gid = group;
1988         }
1989
1990         ret = update_ctime(fs, ino, &inode);
1991         if (ret)
1992                 goto out;
1993
1994         err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
1995                                       sizeof(inode));
1996         if (err) {
1997                 ret = translate_error(fs, ino, err);
1998                 goto out;
1999         }
2000
2001 out:
2002         pthread_mutex_unlock(&ff->bfl);
2003         return ret;
2004 }
2005
2006 static int op_truncate(const char *path, off_t len)
2007 {
2008         struct fuse_context *ctxt = fuse_get_context();
2009         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2010         ext2_filsys fs;
2011         errcode_t err;
2012         ext2_ino_t ino;
2013         ext2_file_t file;
2014         int ret = 0;
2015
2016         FUSE2FS_CHECK_CONTEXT(ff);
2017         fs = ff->fs;
2018         pthread_mutex_lock(&ff->bfl);
2019         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2020         if (err || ino == 0) {
2021                 ret = translate_error(fs, 0, err);
2022                 goto out;
2023         }
2024         dbg_printf("%s: ino=%d len=%jd\n", __func__, ino, len);
2025
2026         ret = check_inum_access(fs, ino, W_OK);
2027         if (ret)
2028                 goto out;
2029
2030         err = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &file);
2031         if (err) {
2032                 ret = translate_error(fs, ino, err);
2033                 goto out;
2034         }
2035
2036         err = ext2fs_file_set_size2(file, len);
2037         if (err) {
2038                 ret = translate_error(fs, ino, err);
2039                 goto out2;
2040         }
2041
2042 out2:
2043         err = ext2fs_file_close(file);
2044         if (ret)
2045                 goto out;
2046         if (err) {
2047                 ret = translate_error(fs, ino, err);
2048                 goto out;
2049         }
2050
2051         ret = update_mtime(fs, ino, NULL);
2052
2053 out:
2054         pthread_mutex_unlock(&ff->bfl);
2055         return err;
2056 }
2057
2058 #ifdef __linux__
2059 static void detect_linux_executable_open(int kernel_flags, int *access_check,
2060                                   int *e2fs_open_flags)
2061 {
2062         /*
2063          * On Linux, execve will bleed __FMODE_EXEC into the file mode flags,
2064          * and FUSE is more than happy to let that slip through.
2065          */
2066         if (kernel_flags & 0x20) {
2067                 *access_check = X_OK;
2068                 *e2fs_open_flags &= ~EXT2_FILE_WRITE;
2069         }
2070 }
2071 #else
2072 static void detect_linux_executable_open(int kernel_flags, int *access_check,
2073                                   int *e2fs_open_flags)
2074 {
2075         /* empty */
2076 }
2077 #endif /* __linux__ */
2078
2079 static int __op_open(struct fuse2fs *ff, const char *path,
2080                      struct fuse_file_info *fp)
2081 {
2082         ext2_filsys fs = ff->fs;
2083         errcode_t err;
2084         struct fuse2fs_file_handle *file;
2085         int check = 0, ret = 0;
2086
2087         dbg_printf("%s: path=%s\n", __func__, path);
2088         err = ext2fs_get_mem(sizeof(*file), &file);
2089         if (err)
2090                 return translate_error(fs, 0, err);
2091         file->magic = FUSE2FS_FILE_MAGIC;
2092
2093         file->open_flags = 0;
2094         switch (fp->flags & O_ACCMODE) {
2095         case O_RDONLY:
2096                 check = R_OK;
2097                 break;
2098         case O_WRONLY:
2099                 check = W_OK;
2100                 file->open_flags |= EXT2_FILE_WRITE;
2101                 break;
2102         case O_RDWR:
2103                 check = R_OK | W_OK;
2104                 file->open_flags |= EXT2_FILE_WRITE;
2105                 break;
2106         }
2107
2108         detect_linux_executable_open(fp->flags, &check, &file->open_flags);
2109
2110         if (fp->flags & O_CREAT)
2111                 file->open_flags |= EXT2_FILE_CREATE;
2112
2113         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &file->ino);
2114         if (err || file->ino == 0) {
2115                 ret = translate_error(fs, 0, err);
2116                 goto out;
2117         }
2118         dbg_printf("%s: ino=%d\n", __func__, file->ino);
2119
2120         ret = check_inum_access(fs, file->ino, check);
2121         if (ret) {
2122                 /*
2123                  * In a regular (Linux) fs driver, the kernel will open
2124                  * binaries for reading if the user has --x privileges (i.e.
2125                  * execute without read).  Since the kernel doesn't have any
2126                  * way to tell us if it's opening a file via execve, we'll
2127                  * just assume that allowing access is ok if asking for ro mode
2128                  * fails but asking for x mode succeeds.  Of course we can
2129                  * also employ undocumented hacks (see above).
2130                  */
2131                 if (check == R_OK) {
2132                         ret = check_inum_access(fs, file->ino, X_OK);
2133                         if (ret)
2134                                 goto out;
2135                 } else
2136                         goto out;
2137         }
2138         fp->fh = (uintptr_t)file;
2139
2140 out:
2141         if (ret)
2142                 ext2fs_free_mem(&file);
2143         return ret;
2144 }
2145
2146 static int op_open(const char *path, struct fuse_file_info *fp)
2147 {
2148         struct fuse_context *ctxt = fuse_get_context();
2149         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2150         int ret;
2151
2152         FUSE2FS_CHECK_CONTEXT(ff);
2153         pthread_mutex_lock(&ff->bfl);
2154         ret = __op_open(ff, path, fp);
2155         pthread_mutex_unlock(&ff->bfl);
2156         return ret;
2157 }
2158
2159 static int op_read(const char *path EXT2FS_ATTR((unused)), char *buf,
2160                    size_t len, off_t offset,
2161                    struct fuse_file_info *fp)
2162 {
2163         struct fuse_context *ctxt = fuse_get_context();
2164         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2165         struct fuse2fs_file_handle *fh =
2166                 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2167         ext2_filsys fs;
2168         ext2_file_t efp;
2169         errcode_t err;
2170         unsigned int got = 0;
2171         int ret = 0;
2172
2173         FUSE2FS_CHECK_CONTEXT(ff);
2174         fs = ff->fs;
2175         FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2176         dbg_printf("%s: ino=%d off=%jd len=%jd\n", __func__, fh->ino, offset,
2177                    len);
2178         pthread_mutex_lock(&ff->bfl);
2179         err = ext2fs_file_open(fs, fh->ino, fh->open_flags, &efp);
2180         if (err) {
2181                 ret = translate_error(fs, fh->ino, err);
2182                 goto out;
2183         }
2184
2185         err = ext2fs_file_llseek(efp, offset, SEEK_SET, NULL);
2186         if (err) {
2187                 ret = translate_error(fs, fh->ino, err);
2188                 goto out2;
2189         }
2190
2191         err = ext2fs_file_read(efp, buf, len, &got);
2192         if (err) {
2193                 ret = translate_error(fs, fh->ino, err);
2194                 goto out2;
2195         }
2196
2197 out2:
2198         err = ext2fs_file_close(efp);
2199         if (ret)
2200                 goto out;
2201         if (err) {
2202                 ret = translate_error(fs, fh->ino, err);
2203                 goto out;
2204         }
2205
2206         if (fs_writeable(fs)) {
2207                 ret = update_atime(fs, fh->ino);
2208                 if (ret)
2209                         goto out;
2210         }
2211 out:
2212         pthread_mutex_unlock(&ff->bfl);
2213         return got ? (int) got : ret;
2214 }
2215
2216 static int op_write(const char *path EXT2FS_ATTR((unused)),
2217                     const char *buf, size_t len, off_t offset,
2218                     struct fuse_file_info *fp)
2219 {
2220         struct fuse_context *ctxt = fuse_get_context();
2221         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2222         struct fuse2fs_file_handle *fh =
2223                 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2224         ext2_filsys fs;
2225         ext2_file_t efp;
2226         errcode_t err;
2227         unsigned int got = 0;
2228         int ret = 0;
2229
2230         FUSE2FS_CHECK_CONTEXT(ff);
2231         fs = ff->fs;
2232         FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2233         dbg_printf("%s: ino=%d off=%jd len=%jd\n", __func__, fh->ino, offset,
2234                    len);
2235         pthread_mutex_lock(&ff->bfl);
2236         if (!fs_writeable(fs)) {
2237                 ret = -EROFS;
2238                 goto out;
2239         }
2240
2241         if (!fs_can_allocate(ff, len / fs->blocksize)) {
2242                 ret = -ENOSPC;
2243                 goto out;
2244         }
2245
2246         err = ext2fs_file_open(fs, fh->ino, fh->open_flags, &efp);
2247         if (err) {
2248                 ret = translate_error(fs, fh->ino, err);
2249                 goto out;
2250         }
2251
2252         err = ext2fs_file_llseek(efp, offset, SEEK_SET, NULL);
2253         if (err) {
2254                 ret = translate_error(fs, fh->ino, err);
2255                 goto out2;
2256         }
2257
2258         err = ext2fs_file_write(efp, buf, len, &got);
2259         if (err) {
2260                 ret = translate_error(fs, fh->ino, err);
2261                 goto out2;
2262         }
2263
2264         err = ext2fs_file_flush(efp);
2265         if (err) {
2266                 got = 0;
2267                 ret = translate_error(fs, fh->ino, err);
2268                 goto out2;
2269         }
2270
2271 out2:
2272         err = ext2fs_file_close(efp);
2273         if (ret)
2274                 goto out;
2275         if (err) {
2276                 ret = translate_error(fs, fh->ino, err);
2277                 goto out;
2278         }
2279
2280         ret = update_mtime(fs, fh->ino, NULL);
2281         if (ret)
2282                 goto out;
2283
2284 out:
2285         pthread_mutex_unlock(&ff->bfl);
2286         return got ? (int) got : ret;
2287 }
2288
2289 static int op_release(const char *path EXT2FS_ATTR((unused)),
2290                       struct fuse_file_info *fp)
2291 {
2292         struct fuse_context *ctxt = fuse_get_context();
2293         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2294         struct fuse2fs_file_handle *fh =
2295                 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2296         ext2_filsys fs;
2297         errcode_t err;
2298         int ret = 0;
2299
2300         FUSE2FS_CHECK_CONTEXT(ff);
2301         fs = ff->fs;
2302         FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2303         dbg_printf("%s: ino=%d\n", __func__, fh->ino);
2304         pthread_mutex_lock(&ff->bfl);
2305         if (fs_writeable(fs) && fh->open_flags & EXT2_FILE_WRITE) {
2306                 err = ext2fs_flush2(fs, EXT2_FLAG_FLUSH_NO_SYNC);
2307                 if (err)
2308                         ret = translate_error(fs, fh->ino, err);
2309         }
2310         fp->fh = 0;
2311         pthread_mutex_unlock(&ff->bfl);
2312
2313         ext2fs_free_mem(&fh);
2314
2315         return ret;
2316 }
2317
2318 static int op_fsync(const char *path EXT2FS_ATTR((unused)),
2319                     int datasync EXT2FS_ATTR((unused)),
2320                     struct fuse_file_info *fp)
2321 {
2322         struct fuse_context *ctxt = fuse_get_context();
2323         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2324         struct fuse2fs_file_handle *fh =
2325                 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2326         ext2_filsys fs;
2327         errcode_t err;
2328         int ret = 0;
2329
2330         FUSE2FS_CHECK_CONTEXT(ff);
2331         fs = ff->fs;
2332         FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2333         dbg_printf("%s: ino=%d\n", __func__, fh->ino);
2334         /* For now, flush everything, even if it's slow */
2335         pthread_mutex_lock(&ff->bfl);
2336         if (fs_writeable(fs) && fh->open_flags & EXT2_FILE_WRITE) {
2337                 err = ext2fs_flush2(fs, 0);
2338                 if (err)
2339                         ret = translate_error(fs, fh->ino, err);
2340         }
2341         pthread_mutex_unlock(&ff->bfl);
2342
2343         return ret;
2344 }
2345
2346 static int op_statfs(const char *path EXT2FS_ATTR((unused)),
2347                      struct statvfs *buf)
2348 {
2349         struct fuse_context *ctxt = fuse_get_context();
2350         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2351         ext2_filsys fs;
2352         uint64_t fsid, *f;
2353         blk64_t overhead, reserved, free;
2354
2355         FUSE2FS_CHECK_CONTEXT(ff);
2356         fs = ff->fs;
2357         dbg_printf("%s: path=%s\n", __func__, path);
2358         buf->f_bsize = fs->blocksize;
2359         buf->f_frsize = 0;
2360
2361         if (ff->minixdf)
2362                 overhead = 0;
2363         else
2364                 overhead = fs->desc_blocks +
2365                            fs->group_desc_count *
2366                            (fs->inode_blocks_per_group + 2);
2367         reserved = ext2fs_r_blocks_count(fs->super);
2368         if (!reserved)
2369                 reserved = ext2fs_blocks_count(fs->super) / 10;
2370         free = ext2fs_free_blocks_count(fs->super);
2371
2372         buf->f_blocks = ext2fs_blocks_count(fs->super) - overhead;
2373         buf->f_bfree = free;
2374         if (free < reserved)
2375                 buf->f_bavail = 0;
2376         else
2377                 buf->f_bavail = free - reserved;
2378         buf->f_files = fs->super->s_inodes_count;
2379         buf->f_ffree = fs->super->s_free_inodes_count;
2380         buf->f_favail = fs->super->s_free_inodes_count;
2381         f = (uint64_t *)fs->super->s_uuid;
2382         fsid = *f;
2383         f++;
2384         fsid ^= *f;
2385         buf->f_fsid = fsid;
2386         buf->f_flag = 0;
2387         if (fs->flags & EXT2_FLAG_RW)
2388                 buf->f_flag |= ST_RDONLY;
2389         buf->f_namemax = EXT2_NAME_LEN;
2390
2391         return 0;
2392 }
2393
2394 typedef errcode_t (*xattr_xlate_get)(void **cooked_buf, size_t *cooked_sz,
2395                                      const void *raw_buf, size_t raw_sz);
2396 typedef errcode_t (*xattr_xlate_set)(const void *cooked_buf, size_t cooked_sz,
2397                                      const void **raw_buf, size_t *raw_sz);
2398 struct xattr_translate {
2399         const char *prefix;
2400         xattr_xlate_get get;
2401         xattr_xlate_set set;
2402 };
2403
2404 #define XATTR_TRANSLATOR(p, g, s) \
2405         {.prefix = (p), \
2406          .get = (xattr_xlate_get)(g), \
2407          .set = (xattr_xlate_set)(s)}
2408
2409 static struct xattr_translate xattr_translators[] = {
2410 #ifdef TRANSLATE_LINUX_ACLS
2411         XATTR_TRANSLATOR(ACL_EA_ACCESS, ext4_to_fuse_acl, fuse_to_ext4_acl),
2412         XATTR_TRANSLATOR(ACL_EA_DEFAULT, ext4_to_fuse_acl, fuse_to_ext4_acl),
2413 #endif
2414         XATTR_TRANSLATOR(NULL, NULL, NULL),
2415 };
2416 #undef XATTR_TRANSLATOR
2417
2418 static int op_getxattr(const char *path, const char *key, char *value,
2419                        size_t len)
2420 {
2421         struct fuse_context *ctxt = fuse_get_context();
2422         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2423         ext2_filsys fs;
2424         struct ext2_xattr_handle *h;
2425         struct xattr_translate *xt;
2426         void *ptr, *cptr;
2427         size_t plen, clen;
2428         ext2_ino_t ino;
2429         errcode_t err;
2430         int ret = 0;
2431
2432         FUSE2FS_CHECK_CONTEXT(ff);
2433         fs = ff->fs;
2434         pthread_mutex_lock(&ff->bfl);
2435         if (!ext2fs_has_feature_xattr(fs->super)) {
2436                 ret = -ENOTSUP;
2437                 goto out;
2438         }
2439
2440         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2441         if (err || ino == 0) {
2442                 ret = translate_error(fs, 0, err);
2443                 goto out;
2444         }
2445         dbg_printf("%s: ino=%d\n", __func__, ino);
2446
2447         ret = check_inum_access(fs, ino, R_OK);
2448         if (ret)
2449                 goto out;
2450
2451         err = ext2fs_xattrs_open(fs, ino, &h);
2452         if (err) {
2453                 ret = translate_error(fs, ino, err);
2454                 goto out;
2455         }
2456
2457         err = ext2fs_xattrs_read(h);
2458         if (err) {
2459                 ret = translate_error(fs, ino, err);
2460                 goto out2;
2461         }
2462
2463         err = ext2fs_xattr_get(h, key, &ptr, &plen);
2464         if (err) {
2465                 ret = translate_error(fs, ino, err);
2466                 goto out2;
2467         }
2468
2469         for (xt = xattr_translators; xt->prefix != NULL; xt++) {
2470                 if (strncmp(key, xt->prefix, strlen(xt->prefix)) == 0) {
2471                         err = xt->get(&cptr, &clen, ptr, plen);
2472                         if (err)
2473                                 goto out3;
2474                         ext2fs_free_mem(&ptr);
2475                         ptr = cptr;
2476                         plen = clen;
2477                 }
2478         }
2479
2480         if (!len) {
2481                 ret = plen;
2482         } else if (len < plen) {
2483                 ret = -ERANGE;
2484         } else {
2485                 memcpy(value, ptr, plen);
2486                 ret = plen;
2487         }
2488
2489 out3:
2490         ext2fs_free_mem(&ptr);
2491 out2:
2492         err = ext2fs_xattrs_close(&h);
2493         if (err)
2494                 ret = translate_error(fs, ino, err);
2495 out:
2496         pthread_mutex_unlock(&ff->bfl);
2497
2498         return ret;
2499 }
2500
2501 static int count_buffer_space(char *name, char *value EXT2FS_ATTR((unused)),
2502                               size_t value_len EXT2FS_ATTR((unused)),
2503                               void *data)
2504 {
2505         unsigned int *x = data;
2506
2507         *x = *x + strlen(name) + 1;
2508         return 0;
2509 }
2510
2511 static int copy_names(char *name, char *value EXT2FS_ATTR((unused)),
2512                       size_t value_len EXT2FS_ATTR((unused)), void *data)
2513 {
2514         char **b = data;
2515
2516         strncpy(*b, name, strlen(name));
2517         *b = *b + strlen(name) + 1;
2518
2519         return 0;
2520 }
2521
2522 static int op_listxattr(const char *path, char *names, size_t len)
2523 {
2524         struct fuse_context *ctxt = fuse_get_context();
2525         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2526         ext2_filsys fs;
2527         struct ext2_xattr_handle *h;
2528         unsigned int bufsz;
2529         ext2_ino_t ino;
2530         errcode_t err;
2531         int ret = 0;
2532
2533         FUSE2FS_CHECK_CONTEXT(ff);
2534         fs = ff->fs;
2535         pthread_mutex_lock(&ff->bfl);
2536         if (!ext2fs_has_feature_xattr(fs->super)) {
2537                 ret = -ENOTSUP;
2538                 goto out;
2539         }
2540
2541         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2542         if (err || ino == 0) {
2543                 ret = translate_error(fs, ino, err);
2544                 goto out;
2545         }
2546         dbg_printf("%s: ino=%d\n", __func__, ino);
2547
2548         ret = check_inum_access(fs, ino, R_OK);
2549         if (ret)
2550                 goto out;
2551
2552         err = ext2fs_xattrs_open(fs, ino, &h);
2553         if (err) {
2554                 ret = translate_error(fs, ino, err);
2555                 goto out;
2556         }
2557
2558         err = ext2fs_xattrs_read(h);
2559         if (err) {
2560                 ret = translate_error(fs, ino, err);
2561                 goto out2;
2562         }
2563
2564         /* Count buffer space needed for names */
2565         bufsz = 0;
2566         err = ext2fs_xattrs_iterate(h, count_buffer_space, &bufsz);
2567         if (err) {
2568                 ret = translate_error(fs, ino, err);
2569                 goto out2;
2570         }
2571
2572         if (len == 0) {
2573                 ret = bufsz;
2574                 goto out2;
2575         } else if (len < bufsz) {
2576                 ret = -ERANGE;
2577                 goto out2;
2578         }
2579
2580         /* Copy names out */
2581         memset(names, 0, len);
2582         err = ext2fs_xattrs_iterate(h, copy_names, &names);
2583         if (err) {
2584                 ret = translate_error(fs, ino, err);
2585                 goto out2;
2586         }
2587         ret = bufsz;
2588 out2:
2589         err = ext2fs_xattrs_close(&h);
2590         if (err)
2591                 ret = translate_error(fs, ino, err);
2592 out:
2593         pthread_mutex_unlock(&ff->bfl);
2594
2595         return ret;
2596 }
2597
2598 static int op_setxattr(const char *path EXT2FS_ATTR((unused)),
2599                        const char *key, const char *value,
2600                        size_t len, int flags EXT2FS_ATTR((unused)))
2601 {
2602         struct fuse_context *ctxt = fuse_get_context();
2603         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2604         ext2_filsys fs;
2605         struct ext2_xattr_handle *h;
2606         struct xattr_translate *xt;
2607         const void *cvalue;
2608         size_t clen;
2609         ext2_ino_t ino;
2610         errcode_t err;
2611         int ret = 0;
2612
2613         FUSE2FS_CHECK_CONTEXT(ff);
2614         fs = ff->fs;
2615         pthread_mutex_lock(&ff->bfl);
2616         if (!ext2fs_has_feature_xattr(fs->super)) {
2617                 ret = -ENOTSUP;
2618                 goto out;
2619         }
2620
2621         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2622         if (err || ino == 0) {
2623                 ret = translate_error(fs, 0, err);
2624                 goto out;
2625         }
2626         dbg_printf("%s: ino=%d\n", __func__, ino);
2627
2628         ret = check_inum_access(fs, ino, W_OK);
2629         if (ret == -EACCES) {
2630                 ret = -EPERM;
2631                 goto out;
2632         } else if (ret)
2633                 goto out;
2634
2635         err = ext2fs_xattrs_open(fs, ino, &h);
2636         if (err) {
2637                 ret = translate_error(fs, ino, err);
2638                 goto out;
2639         }
2640
2641         err = ext2fs_xattrs_read(h);
2642         if (err) {
2643                 ret = translate_error(fs, ino, err);
2644                 goto out2;
2645         }
2646
2647         cvalue = value;
2648         clen = len;
2649         for (xt = xattr_translators; xt->prefix != NULL; xt++) {
2650                 if (strncmp(key, xt->prefix, strlen(xt->prefix)) == 0) {
2651                         err = xt->set(value, len, &cvalue, &clen);
2652                         if (err)
2653                                 goto out3;
2654                 }
2655         }
2656
2657         err = ext2fs_xattr_set(h, key, cvalue, clen);
2658         if (err) {
2659                 ret = translate_error(fs, ino, err);
2660                 goto out3;
2661         }
2662
2663         ret = update_ctime(fs, ino, NULL);
2664 out3:
2665         if (cvalue != value)
2666                 ext2fs_free_mem(&cvalue);
2667 out2:
2668         err = ext2fs_xattrs_close(&h);
2669         if (!ret && err)
2670                 ret = translate_error(fs, ino, err);
2671 out:
2672         pthread_mutex_unlock(&ff->bfl);
2673
2674         return ret;
2675 }
2676
2677 static int op_removexattr(const char *path, const char *key)
2678 {
2679         struct fuse_context *ctxt = fuse_get_context();
2680         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2681         ext2_filsys fs;
2682         struct ext2_xattr_handle *h;
2683         ext2_ino_t ino;
2684         errcode_t err;
2685         int ret = 0;
2686
2687         FUSE2FS_CHECK_CONTEXT(ff);
2688         fs = ff->fs;
2689         pthread_mutex_lock(&ff->bfl);
2690         if (!ext2fs_has_feature_xattr(fs->super)) {
2691                 ret = -ENOTSUP;
2692                 goto out;
2693         }
2694
2695         if (!fs_can_allocate(ff, 1)) {
2696                 ret = -ENOSPC;
2697                 goto out;
2698         }
2699
2700         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2701         if (err || ino == 0) {
2702                 ret = translate_error(fs, 0, err);
2703                 goto out;
2704         }
2705         dbg_printf("%s: ino=%d\n", __func__, ino);
2706
2707         ret = check_inum_access(fs, ino, W_OK);
2708         if (ret)
2709                 goto out;
2710
2711         err = ext2fs_xattrs_open(fs, ino, &h);
2712         if (err) {
2713                 ret = translate_error(fs, ino, err);
2714                 goto out;
2715         }
2716
2717         err = ext2fs_xattrs_read(h);
2718         if (err) {
2719                 ret = translate_error(fs, ino, err);
2720                 goto out2;
2721         }
2722
2723         err = ext2fs_xattr_remove(h, key);
2724         if (err) {
2725                 ret = translate_error(fs, ino, err);
2726                 goto out2;
2727         }
2728
2729         ret = update_ctime(fs, ino, NULL);
2730 out2:
2731         err = ext2fs_xattrs_close(&h);
2732         if (err)
2733                 ret = translate_error(fs, ino, err);
2734 out:
2735         pthread_mutex_unlock(&ff->bfl);
2736
2737         return ret;
2738 }
2739
2740 struct readdir_iter {
2741         void *buf;
2742         fuse_fill_dir_t func;
2743 };
2744
2745 static int op_readdir_iter(ext2_ino_t dir EXT2FS_ATTR((unused)),
2746                            int entry EXT2FS_ATTR((unused)),
2747                            struct ext2_dir_entry *dirent,
2748                            int offset EXT2FS_ATTR((unused)),
2749                            int blocksize EXT2FS_ATTR((unused)),
2750                            char *buf EXT2FS_ATTR((unused)), void *data)
2751 {
2752         struct readdir_iter *i = data;
2753         char namebuf[EXT2_NAME_LEN + 1];
2754         int ret;
2755
2756         memcpy(namebuf, dirent->name, dirent->name_len & 0xFF);
2757         namebuf[dirent->name_len & 0xFF] = 0;
2758         ret = i->func(i->buf, namebuf, NULL, 0);
2759         if (ret)
2760                 return DIRENT_ABORT;
2761
2762         return 0;
2763 }
2764
2765 static int op_readdir(const char *path EXT2FS_ATTR((unused)),
2766                       void *buf, fuse_fill_dir_t fill_func,
2767                       off_t offset EXT2FS_ATTR((unused)),
2768                       struct fuse_file_info *fp)
2769 {
2770         struct fuse_context *ctxt = fuse_get_context();
2771         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2772         struct fuse2fs_file_handle *fh =
2773                 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2774         ext2_filsys fs;
2775         errcode_t err;
2776         struct readdir_iter i;
2777         int ret = 0;
2778
2779         FUSE2FS_CHECK_CONTEXT(ff);
2780         fs = ff->fs;
2781         FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2782         dbg_printf("%s: ino=%d\n", __func__, fh->ino);
2783         pthread_mutex_lock(&ff->bfl);
2784         i.buf = buf;
2785         i.func = fill_func;
2786         err = ext2fs_dir_iterate2(fs, fh->ino, 0, NULL, op_readdir_iter, &i);
2787         if (err) {
2788                 ret = translate_error(fs, fh->ino, err);
2789                 goto out;
2790         }
2791
2792         if (fs_writeable(fs)) {
2793                 ret = update_atime(fs, fh->ino);
2794                 if (ret)
2795                         goto out;
2796         }
2797 out:
2798         pthread_mutex_unlock(&ff->bfl);
2799         return ret;
2800 }
2801
2802 static int op_access(const char *path, int mask)
2803 {
2804         struct fuse_context *ctxt = fuse_get_context();
2805         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2806         ext2_filsys fs;
2807         errcode_t err;
2808         ext2_ino_t ino;
2809         int ret = 0;
2810
2811         FUSE2FS_CHECK_CONTEXT(ff);
2812         fs = ff->fs;
2813         dbg_printf("%s: path=%s mask=0x%x\n", __func__, path, mask);
2814         pthread_mutex_lock(&ff->bfl);
2815         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2816         if (err || ino == 0) {
2817                 ret = translate_error(fs, 0, err);
2818                 goto out;
2819         }
2820
2821         ret = check_inum_access(fs, ino, mask);
2822         if (ret)
2823                 goto out;
2824
2825 out:
2826         pthread_mutex_unlock(&ff->bfl);
2827         return ret;
2828 }
2829
2830 static int op_create(const char *path, mode_t mode, struct fuse_file_info *fp)
2831 {
2832         struct fuse_context *ctxt = fuse_get_context();
2833         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2834         ext2_filsys fs;
2835         ext2_ino_t parent, child;
2836         char *temp_path;
2837         errcode_t err;
2838         char *node_name, a;
2839         int filetype;
2840         struct ext2_inode_large inode;
2841         int ret = 0;
2842
2843         FUSE2FS_CHECK_CONTEXT(ff);
2844         fs = ff->fs;
2845         dbg_printf("%s: path=%s mode=0%o\n", __func__, path, mode);
2846         temp_path = strdup(path);
2847         if (!temp_path) {
2848                 ret = -ENOMEM;
2849                 goto out;
2850         }
2851         node_name = strrchr(temp_path, '/');
2852         if (!node_name) {
2853                 ret = -ENOMEM;
2854                 goto out;
2855         }
2856         node_name++;
2857         a = *node_name;
2858         *node_name = 0;
2859
2860         pthread_mutex_lock(&ff->bfl);
2861         if (!fs_can_allocate(ff, 1)) {
2862                 ret = -ENOSPC;
2863                 goto out2;
2864         }
2865
2866         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
2867                            &parent);
2868         if (err) {
2869                 ret = translate_error(fs, 0, err);
2870                 goto out2;
2871         }
2872
2873         ret = check_inum_access(fs, parent, W_OK);
2874         if (ret)
2875                 goto out2;
2876
2877         *node_name = a;
2878
2879         filetype = ext2_file_type(mode);
2880
2881         err = ext2fs_new_inode(fs, parent, mode, 0, &child);
2882         if (err) {
2883                 ret = translate_error(fs, parent, err);
2884                 goto out2;
2885         }
2886
2887         dbg_printf("%s: creating ino=%d/name=%s in dir=%d\n", __func__, child,
2888                    node_name, parent);
2889         err = ext2fs_link(fs, parent, node_name, child, filetype);
2890         if (err == EXT2_ET_DIR_NO_SPACE) {
2891                 err = ext2fs_expand_dir(fs, parent);
2892                 if (err) {
2893                         ret = translate_error(fs, parent, err);
2894                         goto out2;
2895                 }
2896
2897                 err = ext2fs_link(fs, parent, node_name, child,
2898                                      filetype);
2899         }
2900         if (err) {
2901                 ret = translate_error(fs, parent, err);
2902                 goto out2;
2903         }
2904
2905         ret = update_mtime(fs, parent, NULL);
2906         if (ret)
2907                 goto out2;
2908
2909         memset(&inode, 0, sizeof(inode));
2910         inode.i_mode = mode;
2911         inode.i_links_count = 1;
2912         inode.i_extra_isize = sizeof(struct ext2_inode_large) -
2913                 EXT2_GOOD_OLD_INODE_SIZE;
2914         inode.i_uid = ctxt->uid;
2915         inode.i_gid = ctxt->gid;
2916         if (ext2fs_has_feature_extents(fs->super)) {
2917                 ext2_extent_handle_t handle;
2918
2919                 inode.i_flags &= ~EXT4_EXTENTS_FL;
2920                 ret = ext2fs_extent_open2(fs, child,
2921                                           (struct ext2_inode *)&inode, &handle);
2922                 if (ret)
2923                         return ret;
2924                 ext2fs_extent_free(handle);
2925         }
2926
2927         err = ext2fs_write_new_inode(fs, child, (struct ext2_inode *)&inode);
2928         if (err) {
2929                 ret = translate_error(fs, child, err);
2930                 goto out2;
2931         }
2932
2933         inode.i_generation = ff->next_generation++;
2934         init_times(&inode);
2935         err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode,
2936                                       sizeof(inode));
2937         if (err) {
2938                 ret = translate_error(fs, child, err);
2939                 goto out2;
2940         }
2941
2942         ext2fs_inode_alloc_stats2(fs, child, 1, 0);
2943
2944         ret = __op_open(ff, path, fp);
2945         if (ret)
2946                 goto out2;
2947 out2:
2948         pthread_mutex_unlock(&ff->bfl);
2949 out:
2950         free(temp_path);
2951         return ret;
2952 }
2953
2954 static int op_ftruncate(const char *path EXT2FS_ATTR((unused)),
2955                         off_t len, struct fuse_file_info *fp)
2956 {
2957         struct fuse_context *ctxt = fuse_get_context();
2958         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2959         struct fuse2fs_file_handle *fh =
2960                 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2961         ext2_filsys fs;
2962         ext2_file_t efp;
2963         errcode_t err;
2964         int ret = 0;
2965
2966         FUSE2FS_CHECK_CONTEXT(ff);
2967         fs = ff->fs;
2968         FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2969         dbg_printf("%s: ino=%d len=%jd\n", __func__, fh->ino, len);
2970         pthread_mutex_lock(&ff->bfl);
2971         if (!fs_writeable(fs)) {
2972                 ret = -EROFS;
2973                 goto out;
2974         }
2975
2976         err = ext2fs_file_open(fs, fh->ino, fh->open_flags, &efp);
2977         if (err) {
2978                 ret = translate_error(fs, fh->ino, err);
2979                 goto out;
2980         }
2981
2982         err = ext2fs_file_set_size2(efp, len);
2983         if (err) {
2984                 ret = translate_error(fs, fh->ino, err);
2985                 goto out2;
2986         }
2987
2988 out2:
2989         err = ext2fs_file_close(efp);
2990         if (ret)
2991                 goto out;
2992         if (err) {
2993                 ret = translate_error(fs, fh->ino, err);
2994                 goto out;
2995         }
2996
2997         ret = update_mtime(fs, fh->ino, NULL);
2998         if (ret)
2999                 goto out;
3000
3001 out:
3002         pthread_mutex_unlock(&ff->bfl);
3003         return 0;
3004 }
3005
3006 static int op_fgetattr(const char *path EXT2FS_ATTR((unused)),
3007                        struct stat *statbuf,
3008                        struct fuse_file_info *fp)
3009 {
3010         struct fuse_context *ctxt = fuse_get_context();
3011         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3012         ext2_filsys fs;
3013         struct fuse2fs_file_handle *fh =
3014                 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
3015         int ret = 0;
3016
3017         FUSE2FS_CHECK_CONTEXT(ff);
3018         fs = ff->fs;
3019         FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3020         dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3021         pthread_mutex_lock(&ff->bfl);
3022         ret = stat_inode(fs, fh->ino, statbuf);
3023         pthread_mutex_unlock(&ff->bfl);
3024
3025         return ret;
3026 }
3027
3028 static int op_utimens(const char *path, const struct timespec ctv[2])
3029 {
3030         struct fuse_context *ctxt = fuse_get_context();
3031         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3032         struct timespec tv[2];
3033         ext2_filsys fs;
3034         errcode_t err;
3035         ext2_ino_t ino;
3036         struct ext2_inode_large inode;
3037         int ret = 0;
3038
3039         FUSE2FS_CHECK_CONTEXT(ff);
3040         fs = ff->fs;
3041         pthread_mutex_lock(&ff->bfl);
3042         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
3043         if (err) {
3044                 ret = translate_error(fs, 0, err);
3045                 goto out;
3046         }
3047         dbg_printf("%s: ino=%d\n", __func__, ino);
3048
3049         ret = check_inum_access(fs, ino, W_OK);
3050         if (ret)
3051                 goto out;
3052
3053         memset(&inode, 0, sizeof(inode));
3054         err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
3055                                      sizeof(inode));
3056         if (err) {
3057                 ret = translate_error(fs, ino, err);
3058                 goto out;
3059         }
3060
3061         tv[0] = ctv[0];
3062         tv[1] = ctv[1];
3063 #ifdef UTIME_NOW
3064         if (tv[0].tv_nsec == UTIME_NOW)
3065                 get_now(tv);
3066         if (tv[1].tv_nsec == UTIME_NOW)
3067                 get_now(tv + 1);
3068 #endif /* UTIME_NOW */
3069 #ifdef UTIME_OMIT
3070         if (tv[0].tv_nsec != UTIME_OMIT)
3071                 EXT4_INODE_SET_XTIME(i_atime, tv, &inode);
3072         if (tv[1].tv_nsec != UTIME_OMIT)
3073                 EXT4_INODE_SET_XTIME(i_mtime, tv + 1, &inode);
3074 #endif /* UTIME_OMIT */
3075         ret = update_ctime(fs, ino, &inode);
3076         if (ret)
3077                 goto out;
3078
3079         err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
3080                                       sizeof(inode));
3081         if (err) {
3082                 ret = translate_error(fs, ino, err);
3083                 goto out;
3084         }
3085
3086 out:
3087         pthread_mutex_unlock(&ff->bfl);
3088         return ret;
3089 }
3090
3091 #ifdef SUPPORT_I_FLAGS
3092 static int ioctl_getflags(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3093                           void *data)
3094 {
3095         errcode_t err;
3096         struct ext2_inode_large inode;
3097
3098         FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3099         dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3100         memset(&inode, 0, sizeof(inode));
3101         err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3102                                      sizeof(inode));
3103         if (err)
3104                 return translate_error(fs, fh->ino, err);
3105
3106         *(__u32 *)data = inode.i_flags & EXT2_FL_USER_VISIBLE;
3107         return 0;
3108 }
3109
3110 #define FUSE2FS_MODIFIABLE_IFLAGS \
3111         (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL | EXT2_NODUMP_FL | \
3112          EXT2_NOATIME_FL | EXT3_JOURNAL_DATA_FL | EXT2_DIRSYNC_FL | \
3113          EXT2_TOPDIR_FL)
3114
3115 static int ioctl_setflags(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3116                           void *data)
3117 {
3118         errcode_t err;
3119         struct ext2_inode_large inode;
3120         int ret;
3121         __u32 flags = *(__u32 *)data;
3122         struct fuse_context *ctxt = fuse_get_context();
3123
3124         FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3125         dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3126         memset(&inode, 0, sizeof(inode));
3127         err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3128                                      sizeof(inode));
3129         if (err)
3130                 return translate_error(fs, fh->ino, err);
3131
3132         if (ctxt->uid != 0 && inode.i_uid != ctxt->uid)
3133                 return -EPERM;
3134
3135         if ((inode.i_flags ^ flags) & ~FUSE2FS_MODIFIABLE_IFLAGS)
3136                 return -EINVAL;
3137
3138         inode.i_flags = (inode.i_flags & ~FUSE2FS_MODIFIABLE_IFLAGS) |
3139                         (flags & FUSE2FS_MODIFIABLE_IFLAGS);
3140
3141         ret = update_ctime(fs, fh->ino, &inode);
3142         if (ret)
3143                 return ret;
3144
3145         err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3146                                       sizeof(inode));
3147         if (err)
3148                 return translate_error(fs, fh->ino, err);
3149
3150         return 0;
3151 }
3152
3153 static int ioctl_getversion(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3154                             void *data)
3155 {
3156         errcode_t err;
3157         struct ext2_inode_large inode;
3158
3159         FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3160         dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3161         memset(&inode, 0, sizeof(inode));
3162         err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3163                                      sizeof(inode));
3164         if (err)
3165                 return translate_error(fs, fh->ino, err);
3166
3167         *(__u32 *)data = inode.i_generation;
3168         return 0;
3169 }
3170
3171 static int ioctl_setversion(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3172                             void *data)
3173 {
3174         errcode_t err;
3175         struct ext2_inode_large inode;
3176         int ret;
3177         __u32 generation = *(__u32 *)data;
3178         struct fuse_context *ctxt = fuse_get_context();
3179
3180         FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3181         dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3182         memset(&inode, 0, sizeof(inode));
3183         err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3184                                      sizeof(inode));
3185         if (err)
3186                 return translate_error(fs, fh->ino, err);
3187
3188         if (ctxt->uid != 0 && inode.i_uid != ctxt->uid)
3189                 return -EPERM;
3190
3191         inode.i_generation = generation;
3192
3193         ret = update_ctime(fs, fh->ino, &inode);
3194         if (ret)
3195                 return ret;
3196
3197         err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3198                                       sizeof(inode));
3199         if (err)
3200                 return translate_error(fs, fh->ino, err);
3201
3202         return 0;
3203 }
3204 #endif /* SUPPORT_I_FLAGS */
3205
3206 #ifdef FITRIM
3207 static int ioctl_fitrim(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3208                         void *data)
3209 {
3210         struct fstrim_range *fr = data;
3211         blk64_t start, end, max_blocks, b, cleared;
3212         errcode_t err = 0;
3213
3214         start = fr->start / fs->blocksize;
3215         end = (fr->start + fr->len - 1) / fs->blocksize;
3216         dbg_printf("%s: start=%llu end=%llu\n", __func__, start, end);
3217
3218         if (start < fs->super->s_first_data_block)
3219                 start = fs->super->s_first_data_block;
3220         if (start >= ext2fs_blocks_count(fs->super))
3221                 start = ext2fs_blocks_count(fs->super) - 1;
3222
3223         if (end < fs->super->s_first_data_block)
3224                 end = fs->super->s_first_data_block;
3225         if (end >= ext2fs_blocks_count(fs->super))
3226                 end = ext2fs_blocks_count(fs->super) - 1;
3227
3228         cleared = 0;
3229         max_blocks = 2048ULL * 1024 * 1024 / fs->blocksize;
3230
3231         fr->len = 0;
3232         while (start <= end) {
3233                 err = ext2fs_find_first_zero_block_bitmap2(fs->block_map,
3234                                                            start, end, &start);
3235                 if (err == ENOENT)
3236                         return 0;
3237                 else if (err)
3238                         return translate_error(fs, fh->ino, err);
3239
3240                 b = start + max_blocks < end ? start + max_blocks : end;
3241                 err =  ext2fs_find_first_set_block_bitmap2(fs->block_map,
3242                                                            start, b, &b);
3243                 if (err && err != ENOENT)
3244                         return translate_error(fs, fh->ino, err);
3245                 if (b - start >= fr->minlen) {
3246                         err = io_channel_discard(fs->io, start, b - start);
3247                         if (err)
3248                                 return translate_error(fs, fh->ino, err);
3249                         cleared += b - start;
3250                         fr->len = cleared * fs->blocksize;
3251                 }
3252                 start = b + 1;
3253         }
3254
3255         return err;
3256 }
3257 #endif /* FITRIM */
3258
3259 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
3260 static int op_ioctl(const char *path EXT2FS_ATTR((unused)), int cmd,
3261                     void *arg EXT2FS_ATTR((unused)),
3262                     struct fuse_file_info *fp,
3263                     unsigned int flags EXT2FS_ATTR((unused)), void *data)
3264 {
3265         struct fuse_context *ctxt = fuse_get_context();
3266         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3267         struct fuse2fs_file_handle *fh =
3268                 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
3269         ext2_filsys fs;
3270         int ret = 0;
3271
3272         FUSE2FS_CHECK_CONTEXT(ff);
3273         fs = ff->fs;
3274         pthread_mutex_lock(&ff->bfl);
3275         switch ((unsigned long) cmd) {
3276 #ifdef SUPPORT_I_FLAGS
3277         case EXT2_IOC_GETFLAGS:
3278                 ret = ioctl_getflags(fs, fh, data);
3279                 break;
3280         case EXT2_IOC_SETFLAGS:
3281                 ret = ioctl_setflags(fs, fh, data);
3282                 break;
3283         case EXT2_IOC_GETVERSION:
3284                 ret = ioctl_getversion(fs, fh, data);
3285                 break;
3286         case EXT2_IOC_SETVERSION:
3287                 ret = ioctl_setversion(fs, fh, data);
3288                 break;
3289 #endif
3290 #ifdef FITRIM
3291         case FITRIM:
3292                 ret = ioctl_fitrim(fs, fh, data);
3293                 break;
3294 #endif
3295         default:
3296                 dbg_printf("%s: Unknown ioctl %d\n", __func__, cmd);
3297                 ret = -ENOTTY;
3298         }
3299         pthread_mutex_unlock(&ff->bfl);
3300
3301         return ret;
3302 }
3303 #endif /* FUSE 28 */
3304
3305 static int op_bmap(const char *path, size_t blocksize EXT2FS_ATTR((unused)),
3306                    uint64_t *idx)
3307 {
3308         struct fuse_context *ctxt = fuse_get_context();
3309         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3310         ext2_filsys fs;
3311         ext2_ino_t ino;
3312         errcode_t err;
3313         int ret = 0;
3314
3315         FUSE2FS_CHECK_CONTEXT(ff);
3316         fs = ff->fs;
3317         pthread_mutex_lock(&ff->bfl);
3318         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
3319         if (err) {
3320                 ret = translate_error(fs, 0, err);
3321                 goto out;
3322         }
3323         dbg_printf("%s: ino=%d blk=%"PRIu64"\n", __func__, ino, *idx);
3324
3325         err = ext2fs_bmap2(fs, ino, NULL, NULL, 0, *idx, 0, (blk64_t *)idx);
3326         if (err) {
3327                 ret = translate_error(fs, ino, err);
3328                 goto out;
3329         }
3330
3331 out:
3332         pthread_mutex_unlock(&ff->bfl);
3333         return ret;
3334 }
3335
3336 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
3337 # ifdef SUPPORT_FALLOCATE
3338 static int fallocate_helper(struct fuse_file_info *fp, int mode, off_t offset,
3339                             off_t len)
3340 {
3341         struct fuse_context *ctxt = fuse_get_context();
3342         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3343         struct fuse2fs_file_handle *fh =
3344                 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
3345         ext2_filsys fs;
3346         struct ext2_inode_large inode;
3347         blk64_t start, end;
3348         __u64 fsize;
3349         errcode_t err;
3350         int flags;
3351
3352         FUSE2FS_CHECK_CONTEXT(ff);
3353         fs = ff->fs;
3354         FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3355         start = offset / fs->blocksize;
3356         end = (offset + len - 1) / fs->blocksize;
3357         dbg_printf("%s: ino=%d mode=0x%x start=%jd end=%llu\n", __func__,
3358                    fh->ino, mode, offset / fs->blocksize, end);
3359         if (!fs_can_allocate(ff, len / fs->blocksize))
3360                 return -ENOSPC;
3361
3362         memset(&inode, 0, sizeof(inode));
3363         err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3364                                      sizeof(inode));
3365         if (err)
3366                 return err;
3367         fsize = EXT2_I_SIZE(&inode);
3368
3369         /* Allocate a bunch of blocks */
3370         flags = (mode & FL_KEEP_SIZE_FLAG ? 0 :
3371                         EXT2_FALLOCATE_INIT_BEYOND_EOF);
3372         err = ext2fs_fallocate(fs, flags, fh->ino,
3373                                (struct ext2_inode *)&inode,
3374                                ~0ULL, start, end - start + 1);
3375         if (err && err != EXT2_ET_BLOCK_ALLOC_FAIL)
3376                 return translate_error(fs, fh->ino, err);
3377
3378         /* Update i_size */
3379         if (!(mode & FL_KEEP_SIZE_FLAG)) {
3380                 if ((__u64) offset + len > fsize) {
3381                         err = ext2fs_inode_size_set(fs,
3382                                                 (struct ext2_inode *)&inode,
3383                                                 offset + len);
3384                         if (err)
3385                                 return translate_error(fs, fh->ino, err);
3386                 }
3387         }
3388
3389         err = update_mtime(fs, fh->ino, &inode);
3390         if (err)
3391                 return err;
3392
3393         err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3394                                       sizeof(inode));
3395         if (err)
3396                 return translate_error(fs, fh->ino, err);
3397
3398         return err;
3399 }
3400
3401 static errcode_t clean_block_middle(ext2_filsys fs, ext2_ino_t ino,
3402                                   struct ext2_inode_large *inode, off_t offset,
3403                                   off_t len, char **buf)
3404 {
3405         blk64_t blk;
3406         off_t residue;
3407         int retflags;
3408         errcode_t err;
3409
3410         residue = offset % fs->blocksize;
3411         if (residue == 0)
3412                 return 0;
3413
3414         if (!*buf) {
3415                 err = ext2fs_get_mem(fs->blocksize, buf);
3416                 if (err)
3417                         return err;
3418         }
3419
3420         err = ext2fs_bmap2(fs, ino, (struct ext2_inode *)inode, *buf, 0,
3421                            offset / fs->blocksize, &retflags, &blk);
3422         if (err)
3423                 return err;
3424         if (!blk || (retflags & BMAP_RET_UNINIT))
3425                 return 0;
3426
3427         err = io_channel_read_blk(fs->io, blk, 1, *buf);
3428         if (err)
3429                 return err;
3430
3431         memset(*buf + residue, 0, len);
3432
3433         return io_channel_write_blk(fs->io, blk, 1, *buf);
3434 }
3435
3436 static errcode_t clean_block_edge(ext2_filsys fs, ext2_ino_t ino,
3437                                   struct ext2_inode_large *inode, off_t offset,
3438                                   int clean_before, char **buf)
3439 {
3440         blk64_t blk;
3441         int retflags;
3442         off_t residue;
3443         errcode_t err;
3444
3445         residue = offset % fs->blocksize;
3446         if (residue == 0)
3447                 return 0;
3448
3449         if (!*buf) {
3450                 err = ext2fs_get_mem(fs->blocksize, buf);
3451                 if (err)
3452                         return err;
3453         }
3454
3455         err = ext2fs_bmap2(fs, ino, (struct ext2_inode *)inode, *buf, 0,
3456                            offset / fs->blocksize, &retflags, &blk);
3457         if (err)
3458                 return err;
3459
3460         err = io_channel_read_blk(fs->io, blk, 1, *buf);
3461         if (err)
3462                 return err;
3463         if (!blk || (retflags & BMAP_RET_UNINIT))
3464                 return 0;
3465
3466         if (clean_before)
3467                 memset(*buf, 0, residue);
3468         else
3469                 memset(*buf + residue, 0, fs->blocksize - residue);
3470
3471         return io_channel_write_blk(fs->io, blk, 1, *buf);
3472 }
3473
3474 static int punch_helper(struct fuse_file_info *fp, int mode, off_t offset,
3475                         off_t len)
3476 {
3477         struct fuse_context *ctxt = fuse_get_context();
3478         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3479         struct fuse2fs_file_handle *fh =
3480                 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
3481         ext2_filsys fs;
3482         struct ext2_inode_large inode;
3483         blk64_t start, end;
3484         errcode_t err;
3485         char *buf = NULL;
3486
3487         FUSE2FS_CHECK_CONTEXT(ff);
3488         fs = ff->fs;
3489         FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3490         dbg_printf("%s: offset=%jd len=%jd\n", __func__, offset, len);
3491
3492         /* kernel ext4 punch requires this flag to be set */
3493         if (!(mode & FL_KEEP_SIZE_FLAG))
3494                 return -EINVAL;
3495
3496         /* Punch out a bunch of blocks */
3497         start = (offset + fs->blocksize - 1) / fs->blocksize;
3498         end = (offset + len - fs->blocksize) / fs->blocksize;
3499         dbg_printf("%s: ino=%d mode=0x%x start=%llu end=%llu\n", __func__,
3500                    fh->ino, mode, start, end);
3501
3502         memset(&inode, 0, sizeof(inode));
3503         err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3504                                      sizeof(inode));
3505         if (err)
3506                 return translate_error(fs, fh->ino, err);
3507
3508         /* Zero everything before the first block and after the last block */
3509         if ((offset / fs->blocksize) == ((offset + len) / fs->blocksize))
3510                 err = clean_block_middle(fs, fh->ino, &inode, offset,
3511                                          len, &buf);
3512         else {
3513                 err = clean_block_edge(fs, fh->ino, &inode, offset, 0, &buf);
3514                 if (!err)
3515                         err = clean_block_edge(fs, fh->ino, &inode,
3516                                                offset + len, 1, &buf);
3517         }
3518         if (buf)
3519                 ext2fs_free_mem(&buf);
3520         if (err)
3521                 return translate_error(fs, fh->ino, err);
3522
3523         /* Unmap full blocks in the middle */
3524         if (start <= end) {
3525                 err = ext2fs_punch(fs, fh->ino, (struct ext2_inode *)&inode,
3526                                    NULL, start, end);
3527                 if (err)
3528                         return translate_error(fs, fh->ino, err);
3529         }
3530
3531         err = update_mtime(fs, fh->ino, &inode);
3532         if (err)
3533                 return err;
3534
3535         err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3536                                       sizeof(inode));
3537         if (err)
3538                 return translate_error(fs, fh->ino, err);
3539
3540         return 0;
3541 }
3542
3543 static int op_fallocate(const char *path EXT2FS_ATTR((unused)), int mode,
3544                         off_t offset, off_t len,
3545                         struct fuse_file_info *fp)
3546 {
3547         struct fuse_context *ctxt = fuse_get_context();
3548         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3549         ext2_filsys fs = ff->fs;
3550         int ret;
3551
3552         /* Catch unknown flags */
3553         if (mode & ~(FL_PUNCH_HOLE_FLAG | FL_KEEP_SIZE_FLAG))
3554                 return -EINVAL;
3555
3556         pthread_mutex_lock(&ff->bfl);
3557         if (!fs_writeable(fs)) {
3558                 ret = -EROFS;
3559                 goto out;
3560         }
3561         if (mode & FL_PUNCH_HOLE_FLAG)
3562                 ret = punch_helper(fp, mode, offset, len);
3563         else
3564                 ret = fallocate_helper(fp, mode, offset, len);
3565 out:
3566         pthread_mutex_unlock(&ff->bfl);
3567
3568         return ret;
3569 }
3570 # endif /* SUPPORT_FALLOCATE */
3571 #endif /* FUSE 29 */
3572
3573 static struct fuse_operations fs_ops = {
3574         .init = op_init,
3575         .destroy = op_destroy,
3576         .getattr = op_getattr,
3577         .readlink = op_readlink,
3578         .mknod = op_mknod,
3579         .mkdir = op_mkdir,
3580         .unlink = op_unlink,
3581         .rmdir = op_rmdir,
3582         .symlink = op_symlink,
3583         .rename = op_rename,
3584         .link = op_link,
3585         .chmod = op_chmod,
3586         .chown = op_chown,
3587         .truncate = op_truncate,
3588         .open = op_open,
3589         .read = op_read,
3590         .write = op_write,
3591         .statfs = op_statfs,
3592         .release = op_release,
3593         .fsync = op_fsync,
3594         .setxattr = op_setxattr,
3595         .getxattr = op_getxattr,
3596         .listxattr = op_listxattr,
3597         .removexattr = op_removexattr,
3598         .opendir = op_open,
3599         .readdir = op_readdir,
3600         .releasedir = op_release,
3601         .fsyncdir = op_fsync,
3602         .access = op_access,
3603         .create = op_create,
3604         .ftruncate = op_ftruncate,
3605         .fgetattr = op_fgetattr,
3606         .utimens = op_utimens,
3607 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
3608 # if defined(UTIME_NOW) || defined(UTIME_OMIT)
3609         .flag_utime_omit_ok = 1,
3610 # endif
3611 #endif
3612         .bmap = op_bmap,
3613 #ifdef SUPERFLUOUS
3614         .lock = op_lock,
3615         .poll = op_poll,
3616 #endif
3617 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
3618         .ioctl = op_ioctl,
3619         .flag_nullpath_ok = 1,
3620 #endif
3621 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
3622         .flag_nopath = 1,
3623 # ifdef SUPPORT_FALLOCATE
3624         .fallocate = op_fallocate,
3625 # endif
3626 #endif
3627 };
3628
3629 static int get_random_bytes(void *p, size_t sz)
3630 {
3631         int fd;
3632         ssize_t r;
3633
3634         fd = open("/dev/urandom", O_RDONLY);
3635         if (fd < 0) {
3636                 perror("/dev/urandom");
3637                 return 0;
3638         }
3639
3640         r = read(fd, p, sz);
3641
3642         close(fd);
3643         return (size_t) r == sz;
3644 }
3645
3646 enum {
3647         FUSE2FS_VERSION,
3648         FUSE2FS_HELP,
3649         FUSE2FS_HELPFULL,
3650 };
3651
3652 #define FUSE2FS_OPT(t, p, v) { t, offsetof(struct fuse2fs, p), v }
3653
3654 static struct fuse_opt fuse2fs_opts[] = {
3655         FUSE2FS_OPT("ro",               ro,                     1),
3656         FUSE2FS_OPT("errors=panic",     panic_on_error,         1),
3657         FUSE2FS_OPT("minixdf",          minixdf,                1),
3658         FUSE2FS_OPT("fuse2fs_debug",    debug,                  1),
3659         FUSE2FS_OPT("no_default_opts",  no_default_opts,        1),
3660
3661         FUSE_OPT_KEY("-V",             FUSE2FS_VERSION),
3662         FUSE_OPT_KEY("--version",      FUSE2FS_VERSION),
3663         FUSE_OPT_KEY("-h",             FUSE2FS_HELP),
3664         FUSE_OPT_KEY("--help",         FUSE2FS_HELP),
3665         FUSE_OPT_KEY("--helpfull",     FUSE2FS_HELPFULL),
3666         FUSE_OPT_END
3667 };
3668
3669
3670 static int fuse2fs_opt_proc(void *data, const char *arg,
3671                             int key, struct fuse_args *outargs)
3672 {
3673         struct fuse2fs *ff = data;
3674
3675         switch (key) {
3676         case FUSE_OPT_KEY_NONOPT:
3677                 if (!ff->device) {
3678                         ff->device = strdup(arg);
3679                         return 0;
3680                 }
3681                 return 1;
3682         case FUSE2FS_HELP:
3683         case FUSE2FS_HELPFULL:
3684                 fprintf(stderr,
3685         "usage: %s device/image mountpoint [options]\n"
3686         "\n"
3687         "general options:\n"
3688         "    -o opt,[opt...]  mount options\n"
3689         "    -h   --help      print help\n"
3690         "    -V   --version   print version\n"
3691         "\n"
3692         "fuse2fs options:\n"
3693         "    -o ro                  read-only mount\n"
3694         "    -o errors=panic        dump core on error\n"
3695         "    -o minixdf             minix-style df\n"
3696         "    -o no_default_opts     do not include default fuse options\n"
3697         "    -o fuse2fs_debug       enable fuse2fs debugging\n"
3698         "\n",
3699                         outargs->argv[0]);
3700                 if (key == FUSE2FS_HELPFULL) {
3701                         fuse_opt_add_arg(outargs, "-ho");
3702                         fuse_main(outargs->argc, outargs->argv, &fs_ops, NULL);
3703                 } else {
3704                         fprintf(stderr, "Try --helpfull to get a list of "
3705                                 "all flags, including the FUSE options.\n");
3706                 }
3707                 exit(1);
3708
3709         case FUSE2FS_VERSION:
3710                 fprintf(stderr, "fuse2fs %s (%s)\n", E2FSPROGS_VERSION,
3711                         E2FSPROGS_DATE);
3712                 fuse_opt_add_arg(outargs, "--version");
3713                 fuse_main(outargs->argc, outargs->argv, &fs_ops, NULL);
3714                 exit(0);
3715         }
3716         return 1;
3717 }
3718
3719 int main(int argc, char *argv[])
3720 {
3721         struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
3722         struct fuse2fs fctx;
3723         errcode_t err;
3724         char *logfile;
3725         char extra_args[BUFSIZ];
3726         int ret = 0, flags = EXT2_FLAG_64BITS | EXT2_FLAG_EXCLUSIVE;
3727
3728         memset(&fctx, 0, sizeof(fctx));
3729         fctx.magic = FUSE2FS_MAGIC;
3730
3731         fuse_opt_parse(&args, &fctx, fuse2fs_opts, fuse2fs_opt_proc);
3732         if (fctx.device == NULL) {
3733                 fprintf(stderr, "Missing ext4 device/image\n");
3734                 fprintf(stderr, "See '%s -h' for usage\n", argv[0]);
3735                 exit(1);
3736         }
3737
3738         if (fctx.ro)
3739                 printf("%s", _("Mounting read-only.\n"));
3740
3741 #ifdef ENABLE_NLS
3742         setlocale(LC_MESSAGES, "");
3743         setlocale(LC_CTYPE, "");
3744         bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
3745         textdomain(NLS_CAT_NAME);
3746         set_com_err_gettext(gettext);
3747 #endif
3748         add_error_table(&et_ext2_error_table);
3749
3750         /* Set up error logging */
3751         logfile = getenv("FUSE2FS_LOGFILE");
3752         if (logfile) {
3753                 fctx.err_fp = fopen(logfile, "a");
3754                 if (!fctx.err_fp) {
3755                         perror(logfile);
3756                         goto out;
3757                 }
3758         } else
3759                 fctx.err_fp = stderr;
3760
3761         /* Will we allow users to allocate every last block? */
3762         if (getenv("FUSE2FS_ALLOC_ALL_BLOCKS")) {
3763                 printf(_("%s: Allowing users to allocate all blocks. "
3764                        "This is dangerous!\n"), fctx.device);
3765                 fctx.alloc_all_blocks = 1;
3766         }
3767
3768         /* Start up the fs (while we still can use stdout) */
3769         ret = 2;
3770         if (!fctx.ro)
3771                 flags |= EXT2_FLAG_RW;
3772         err = ext2fs_open2(fctx.device, NULL, flags, 0, 0, unix_io_manager,
3773                            &global_fs);
3774         if (err) {
3775                 printf(_("%s: %s.\n"), fctx.device, error_message(err));
3776                 printf(_("Please run e2fsck -fy %s.\n"), fctx.device);
3777                 goto out;
3778         }
3779         fctx.fs = global_fs;
3780         global_fs->priv_data = &fctx;
3781
3782         ret = 3;
3783
3784         if (ext2fs_has_feature_journal_needs_recovery(global_fs->super)) {
3785                 if (!fctx.ro) {
3786                         printf(_("%s: recovering journal\n"), fctx.device);
3787                         err = ext2fs_run_ext3_journal(&global_fs);
3788                         if (err) {
3789                                 printf(_("%s: %s.\n"), fctx.device,
3790                                        error_message(err));
3791                                 printf(_("Please run e2fsck -fy %s.\n"),
3792                                        fctx.device);
3793                                 goto out;
3794                         }
3795                         ext2fs_clear_feature_journal_needs_recovery(global_fs->super);
3796                         ext2fs_mark_super_dirty(global_fs);
3797                 } else {
3798                         printf("%s", _("Journal needs recovery; running "
3799                                "`e2fsck -E journal_only' is required.\n"));
3800                         goto out;
3801                 }
3802         }
3803
3804         if (!fctx.ro) {
3805                 if (ext2fs_has_feature_journal(global_fs->super))
3806                         printf(_("%s: Writing to the journal is not supported.\n"),
3807                                fctx.device);
3808                 err = ext2fs_read_inode_bitmap(global_fs);
3809                 if (err) {
3810                         translate_error(global_fs, 0, err);
3811                         goto out;
3812                 }
3813                 err = ext2fs_read_block_bitmap(global_fs);
3814                 if (err) {
3815                         translate_error(global_fs, 0, err);
3816                         goto out;
3817                 }
3818         }
3819
3820         if (!(global_fs->super->s_state & EXT2_VALID_FS))
3821                 printf("%s", _("Warning: Mounting unchecked fs, running e2fsck "
3822                        "is recommended.\n"));
3823         if (global_fs->super->s_max_mnt_count > 0 &&
3824             global_fs->super->s_mnt_count >= global_fs->super->s_max_mnt_count)
3825                 printf("%s", _("Warning: Maximal mount count reached, running "
3826                        "e2fsck is recommended.\n"));
3827         if (global_fs->super->s_checkinterval > 0 &&
3828             (time_t) (global_fs->super->s_lastcheck +
3829                       global_fs->super->s_checkinterval) <= time(0))
3830                 printf("%s", _("Warning: Check time reached; running e2fsck "
3831                        "is recommended.\n"));
3832         if (global_fs->super->s_last_orphan)
3833                 printf("%s",
3834                        _("Orphans detected; running e2fsck is recommended.\n"));
3835
3836         if (global_fs->super->s_state & EXT2_ERROR_FS) {
3837                 printf("%s",
3838                        _("Errors detected; running e2fsck is required.\n"));
3839                 goto out;
3840         }
3841
3842         /* Initialize generation counter */
3843         get_random_bytes(&fctx.next_generation, sizeof(unsigned int));
3844
3845         /* Set up default fuse parameters */
3846         snprintf(extra_args, BUFSIZ, "-okernel_cache,subtype=ext4,use_ino,"
3847                  "fsname=%s,attr_timeout=0" FUSE_PLATFORM_OPTS,
3848                  argv[1]);
3849         if (fctx.no_default_opts == 0)
3850                 fuse_opt_add_arg(&args, extra_args);
3851
3852         if (fctx.debug) {
3853                 int     i;
3854
3855                 printf("fuse arguments:");
3856                 for (i = 0; i < args.argc; i++)
3857                         printf(" '%s'", args.argv[i]);
3858                 printf("\n");
3859         }
3860
3861         pthread_mutex_init(&fctx.bfl, NULL);
3862         fuse_main(args.argc, args.argv, &fs_ops, &fctx);
3863         pthread_mutex_destroy(&fctx.bfl);
3864
3865         ret = 0;
3866 out:
3867         if (global_fs) {
3868                 err = ext2fs_close(global_fs);
3869                 if (err)
3870                         com_err(argv[0], err, "while closing fs");
3871                 global_fs = NULL;
3872         }
3873         return ret;
3874 }
3875
3876 static int __translate_error(ext2_filsys fs, errcode_t err, ext2_ino_t ino,
3877                              const char *file, int line)
3878 {
3879         struct timespec now;
3880         int ret = err;
3881         struct fuse2fs *ff = fs->priv_data;
3882         int is_err = 0;
3883
3884         /* Translate ext2 error to unix error code */
3885         if (err < EXT2_ET_BASE)
3886                 goto no_translation;
3887         switch (err) {
3888         case EXT2_ET_NO_MEMORY:
3889         case EXT2_ET_TDB_ERR_OOM:
3890                 ret = -ENOMEM;
3891                 break;
3892         case EXT2_ET_INVALID_ARGUMENT:
3893         case EXT2_ET_LLSEEK_FAILED:
3894                 ret = -EINVAL;
3895                 break;
3896         case EXT2_ET_NO_DIRECTORY:
3897                 ret = -ENOTDIR;
3898                 break;
3899         case EXT2_ET_FILE_NOT_FOUND:
3900                 ret = -ENOENT;
3901                 break;
3902         case EXT2_ET_DIR_NO_SPACE:
3903                 is_err = 1;
3904                 /* fallthrough */
3905         case EXT2_ET_TOOSMALL:
3906         case EXT2_ET_BLOCK_ALLOC_FAIL:
3907         case EXT2_ET_INODE_ALLOC_FAIL:
3908         case EXT2_ET_EA_NO_SPACE:
3909                 ret = -ENOSPC;
3910                 break;
3911         case EXT2_ET_SYMLINK_LOOP:
3912                 ret = -EMLINK;
3913                 break;
3914         case EXT2_ET_FILE_TOO_BIG:
3915                 ret = -EFBIG;
3916                 break;
3917         case EXT2_ET_TDB_ERR_EXISTS:
3918         case EXT2_ET_FILE_EXISTS:
3919                 ret = -EEXIST;
3920                 break;
3921         case EXT2_ET_MMP_FAILED:
3922         case EXT2_ET_MMP_FSCK_ON:
3923                 ret = -EBUSY;
3924                 break;
3925         case EXT2_ET_EA_KEY_NOT_FOUND:
3926 #ifdef ENODATA
3927                 ret = -ENODATA;
3928 #else
3929                 ret = -ENOENT;
3930 #endif
3931                 break;
3932         /* Sometimes fuse returns a garbage file handle pointer to us... */
3933         case EXT2_ET_MAGIC_EXT2_FILE:
3934                 ret = -EFAULT;
3935                 break;
3936         case EXT2_ET_UNIMPLEMENTED:
3937                 ret = -EOPNOTSUPP;
3938                 break;
3939         default:
3940                 is_err = 1;
3941                 ret = -EIO;
3942                 break;
3943         }
3944
3945 no_translation:
3946         if (!is_err)
3947                 return ret;
3948
3949         if (ino)
3950                 fprintf(ff->err_fp, "FUSE2FS (%s): %s (inode #%d) at %s:%d.\n",
3951                         fs->device_name ? fs->device_name : "???",
3952                         error_message(err), ino, file, line);
3953         else
3954                 fprintf(ff->err_fp, "FUSE2FS (%s): %s at %s:%d.\n",
3955                         fs->device_name ? fs->device_name : "???",
3956                         error_message(err), file, line);
3957         fflush(ff->err_fp);
3958
3959         /* Make a note in the error log */
3960         get_now(&now);
3961         fs->super->s_last_error_time = now.tv_sec;
3962         fs->super->s_last_error_ino = ino;
3963         fs->super->s_last_error_line = line;
3964         fs->super->s_last_error_block = err; /* Yeah... */
3965         strncpy((char *)fs->super->s_last_error_func, file,
3966                 sizeof(fs->super->s_last_error_func));
3967         if (fs->super->s_first_error_time == 0) {
3968                 fs->super->s_first_error_time = now.tv_sec;
3969                 fs->super->s_first_error_ino = ino;
3970                 fs->super->s_first_error_line = line;
3971                 fs->super->s_first_error_block = err;
3972                 strncpy((char *)fs->super->s_first_error_func, file,
3973                         sizeof(fs->super->s_first_error_func));
3974         }
3975
3976         fs->super->s_error_count++;
3977         ext2fs_mark_super_dirty(fs);
3978         ext2fs_flush(fs);
3979         if (ff->panic_on_error)
3980                 abort();
3981
3982         return ret;
3983 }