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