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