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