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