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