Whamcloud - gitweb
084ba2829ad1199185be74828505711df977846a
[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                               ext2_ino_t inode_num EXT2FS_ATTR((unused)),
2530                               void *data)
2531 {
2532         unsigned int *x = data;
2533
2534         *x = *x + strlen(name) + 1;
2535         return 0;
2536 }
2537
2538 static int copy_names(char *name, char *value EXT2FS_ATTR((unused)),
2539                       size_t value_len EXT2FS_ATTR((unused)),
2540                       ext2_ino_t inode_num EXT2FS_ATTR((unused)),
2541                       void *data)
2542 {
2543         char **b = data;
2544         size_t name_len = strlen(name);
2545
2546         memcpy(*b, name, name_len + 1);
2547         *b = *b + name_len + 1;
2548
2549         return 0;
2550 }
2551
2552 static int op_listxattr(const char *path, char *names, size_t len)
2553 {
2554         struct fuse_context *ctxt = fuse_get_context();
2555         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2556         ext2_filsys fs;
2557         struct ext2_xattr_handle *h;
2558         unsigned int bufsz;
2559         ext2_ino_t ino;
2560         errcode_t err;
2561         int ret = 0;
2562
2563         FUSE2FS_CHECK_CONTEXT(ff);
2564         fs = ff->fs;
2565         pthread_mutex_lock(&ff->bfl);
2566         if (!ext2fs_has_feature_xattr(fs->super)) {
2567                 ret = -ENOTSUP;
2568                 goto out;
2569         }
2570
2571         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2572         if (err || ino == 0) {
2573                 ret = translate_error(fs, ino, err);
2574                 goto out;
2575         }
2576         dbg_printf("%s: ino=%d\n", __func__, ino);
2577
2578         ret = check_inum_access(fs, ino, R_OK);
2579         if (ret)
2580                 goto out;
2581
2582         err = ext2fs_xattrs_open(fs, ino, &h);
2583         if (err) {
2584                 ret = translate_error(fs, ino, err);
2585                 goto out;
2586         }
2587
2588         err = ext2fs_xattrs_read(h);
2589         if (err) {
2590                 ret = translate_error(fs, ino, err);
2591                 goto out2;
2592         }
2593
2594         /* Count buffer space needed for names */
2595         bufsz = 0;
2596         err = ext2fs_xattrs_iterate(h, count_buffer_space, &bufsz);
2597         if (err) {
2598                 ret = translate_error(fs, ino, err);
2599                 goto out2;
2600         }
2601
2602         if (len == 0) {
2603                 ret = bufsz;
2604                 goto out2;
2605         } else if (len < bufsz) {
2606                 ret = -ERANGE;
2607                 goto out2;
2608         }
2609
2610         /* Copy names out */
2611         memset(names, 0, len);
2612         err = ext2fs_xattrs_iterate(h, copy_names, &names);
2613         if (err) {
2614                 ret = translate_error(fs, ino, err);
2615                 goto out2;
2616         }
2617         ret = bufsz;
2618 out2:
2619         err = ext2fs_xattrs_close(&h);
2620         if (err)
2621                 ret = translate_error(fs, ino, err);
2622 out:
2623         pthread_mutex_unlock(&ff->bfl);
2624
2625         return ret;
2626 }
2627
2628 static int op_setxattr(const char *path EXT2FS_ATTR((unused)),
2629                        const char *key, const char *value,
2630                        size_t len, int flags EXT2FS_ATTR((unused)))
2631 {
2632         struct fuse_context *ctxt = fuse_get_context();
2633         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2634         ext2_filsys fs;
2635         struct ext2_xattr_handle *h;
2636         struct xattr_translate *xt;
2637         const void *cvalue;
2638         size_t clen;
2639         ext2_ino_t ino;
2640         errcode_t err;
2641         int ret = 0;
2642
2643         FUSE2FS_CHECK_CONTEXT(ff);
2644         fs = ff->fs;
2645         pthread_mutex_lock(&ff->bfl);
2646         if (!ext2fs_has_feature_xattr(fs->super)) {
2647                 ret = -ENOTSUP;
2648                 goto out;
2649         }
2650
2651         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2652         if (err || ino == 0) {
2653                 ret = translate_error(fs, 0, err);
2654                 goto out;
2655         }
2656         dbg_printf("%s: ino=%d\n", __func__, ino);
2657
2658         ret = check_inum_access(fs, ino, W_OK);
2659         if (ret == -EACCES) {
2660                 ret = -EPERM;
2661                 goto out;
2662         } else if (ret)
2663                 goto out;
2664
2665         err = ext2fs_xattrs_open(fs, ino, &h);
2666         if (err) {
2667                 ret = translate_error(fs, ino, err);
2668                 goto out;
2669         }
2670
2671         err = ext2fs_xattrs_read(h);
2672         if (err) {
2673                 ret = translate_error(fs, ino, err);
2674                 goto out2;
2675         }
2676
2677         cvalue = value;
2678         clen = len;
2679         for (xt = xattr_translators; xt->prefix != NULL; xt++) {
2680                 if (strncmp(key, xt->prefix, strlen(xt->prefix)) == 0) {
2681                         err = xt->set(value, len, &cvalue, &clen);
2682                         if (err)
2683                                 goto out3;
2684                 }
2685         }
2686
2687         err = ext2fs_xattr_set(h, key, cvalue, clen);
2688         if (err) {
2689                 ret = translate_error(fs, ino, err);
2690                 goto out3;
2691         }
2692
2693         ret = update_ctime(fs, ino, NULL);
2694 out3:
2695         if (cvalue != value)
2696                 ext2fs_free_mem(&cvalue);
2697 out2:
2698         err = ext2fs_xattrs_close(&h);
2699         if (!ret && err)
2700                 ret = translate_error(fs, ino, err);
2701 out:
2702         pthread_mutex_unlock(&ff->bfl);
2703
2704         return ret;
2705 }
2706
2707 static int op_removexattr(const char *path, const char *key)
2708 {
2709         struct fuse_context *ctxt = fuse_get_context();
2710         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2711         ext2_filsys fs;
2712         struct ext2_xattr_handle *h;
2713         ext2_ino_t ino;
2714         errcode_t err;
2715         int ret = 0;
2716
2717         FUSE2FS_CHECK_CONTEXT(ff);
2718         fs = ff->fs;
2719         pthread_mutex_lock(&ff->bfl);
2720         if (!ext2fs_has_feature_xattr(fs->super)) {
2721                 ret = -ENOTSUP;
2722                 goto out;
2723         }
2724
2725         if (!fs_can_allocate(ff, 1)) {
2726                 ret = -ENOSPC;
2727                 goto out;
2728         }
2729
2730         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2731         if (err || ino == 0) {
2732                 ret = translate_error(fs, 0, err);
2733                 goto out;
2734         }
2735         dbg_printf("%s: ino=%d\n", __func__, ino);
2736
2737         ret = check_inum_access(fs, ino, W_OK);
2738         if (ret)
2739                 goto out;
2740
2741         err = ext2fs_xattrs_open(fs, ino, &h);
2742         if (err) {
2743                 ret = translate_error(fs, ino, err);
2744                 goto out;
2745         }
2746
2747         err = ext2fs_xattrs_read(h);
2748         if (err) {
2749                 ret = translate_error(fs, ino, err);
2750                 goto out2;
2751         }
2752
2753         err = ext2fs_xattr_remove(h, key);
2754         if (err) {
2755                 ret = translate_error(fs, ino, err);
2756                 goto out2;
2757         }
2758
2759         ret = update_ctime(fs, ino, NULL);
2760 out2:
2761         err = ext2fs_xattrs_close(&h);
2762         if (err)
2763                 ret = translate_error(fs, ino, err);
2764 out:
2765         pthread_mutex_unlock(&ff->bfl);
2766
2767         return ret;
2768 }
2769
2770 struct readdir_iter {
2771         void *buf;
2772         fuse_fill_dir_t func;
2773 };
2774
2775 static int op_readdir_iter(ext2_ino_t dir EXT2FS_ATTR((unused)),
2776                            int entry EXT2FS_ATTR((unused)),
2777                            struct ext2_dir_entry *dirent,
2778                            int offset EXT2FS_ATTR((unused)),
2779                            int blocksize EXT2FS_ATTR((unused)),
2780                            char *buf EXT2FS_ATTR((unused)), void *data)
2781 {
2782         struct readdir_iter *i = data;
2783         char namebuf[EXT2_NAME_LEN + 1];
2784         int ret;
2785
2786         memcpy(namebuf, dirent->name, dirent->name_len & 0xFF);
2787         namebuf[dirent->name_len & 0xFF] = 0;
2788         ret = i->func(i->buf, namebuf, NULL, 0
2789 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
2790                         , 0
2791 #endif
2792                         );
2793         if (ret)
2794                 return DIRENT_ABORT;
2795
2796         return 0;
2797 }
2798
2799 static int op_readdir(const char *path EXT2FS_ATTR((unused)),
2800                       void *buf, fuse_fill_dir_t fill_func,
2801                       off_t offset EXT2FS_ATTR((unused)),
2802                       struct fuse_file_info *fp
2803 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
2804                         , enum fuse_readdir_flags flags EXT2FS_ATTR((unused))
2805 #endif
2806                         )
2807 {
2808         struct fuse_context *ctxt = fuse_get_context();
2809         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2810         struct fuse2fs_file_handle *fh =
2811                 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2812         ext2_filsys fs;
2813         errcode_t err;
2814         struct readdir_iter i;
2815         int ret = 0;
2816
2817         FUSE2FS_CHECK_CONTEXT(ff);
2818         fs = ff->fs;
2819         FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2820         dbg_printf("%s: ino=%d\n", __func__, fh->ino);
2821         pthread_mutex_lock(&ff->bfl);
2822         i.buf = buf;
2823         i.func = fill_func;
2824         err = ext2fs_dir_iterate2(fs, fh->ino, 0, NULL, op_readdir_iter, &i);
2825         if (err) {
2826                 ret = translate_error(fs, fh->ino, err);
2827                 goto out;
2828         }
2829
2830         if (fs_writeable(fs)) {
2831                 ret = update_atime(fs, fh->ino);
2832                 if (ret)
2833                         goto out;
2834         }
2835 out:
2836         pthread_mutex_unlock(&ff->bfl);
2837         return ret;
2838 }
2839
2840 static int op_access(const char *path, int mask)
2841 {
2842         struct fuse_context *ctxt = fuse_get_context();
2843         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2844         ext2_filsys fs;
2845         errcode_t err;
2846         ext2_ino_t ino;
2847         int ret = 0;
2848
2849         FUSE2FS_CHECK_CONTEXT(ff);
2850         fs = ff->fs;
2851         dbg_printf("%s: path=%s mask=0x%x\n", __func__, path, mask);
2852         pthread_mutex_lock(&ff->bfl);
2853         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2854         if (err || ino == 0) {
2855                 ret = translate_error(fs, 0, err);
2856                 goto out;
2857         }
2858
2859         ret = check_inum_access(fs, ino, mask);
2860         if (ret)
2861                 goto out;
2862
2863 out:
2864         pthread_mutex_unlock(&ff->bfl);
2865         return ret;
2866 }
2867
2868 static int op_create(const char *path, mode_t mode, struct fuse_file_info *fp)
2869 {
2870         struct fuse_context *ctxt = fuse_get_context();
2871         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2872         ext2_filsys fs;
2873         ext2_ino_t parent, child;
2874         char *temp_path;
2875         errcode_t err;
2876         char *node_name, a;
2877         int filetype;
2878         struct ext2_inode_large inode;
2879         int ret = 0;
2880
2881         FUSE2FS_CHECK_CONTEXT(ff);
2882         fs = ff->fs;
2883         dbg_printf("%s: path=%s mode=0%o\n", __func__, path, mode);
2884         temp_path = strdup(path);
2885         if (!temp_path) {
2886                 ret = -ENOMEM;
2887                 goto out;
2888         }
2889         node_name = strrchr(temp_path, '/');
2890         if (!node_name) {
2891                 ret = -ENOMEM;
2892                 goto out;
2893         }
2894         node_name++;
2895         a = *node_name;
2896         *node_name = 0;
2897
2898         pthread_mutex_lock(&ff->bfl);
2899         if (!fs_can_allocate(ff, 1)) {
2900                 ret = -ENOSPC;
2901                 goto out2;
2902         }
2903
2904         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
2905                            &parent);
2906         if (err) {
2907                 ret = translate_error(fs, 0, err);
2908                 goto out2;
2909         }
2910
2911         ret = check_inum_access(fs, parent, W_OK);
2912         if (ret)
2913                 goto out2;
2914
2915         *node_name = a;
2916
2917         filetype = ext2_file_type(mode);
2918
2919         err = ext2fs_new_inode(fs, parent, mode, 0, &child);
2920         if (err) {
2921                 ret = translate_error(fs, parent, err);
2922                 goto out2;
2923         }
2924
2925         dbg_printf("%s: creating ino=%d/name=%s in dir=%d\n", __func__, child,
2926                    node_name, parent);
2927         err = ext2fs_link(fs, parent, node_name, child, filetype);
2928         if (err == EXT2_ET_DIR_NO_SPACE) {
2929                 err = ext2fs_expand_dir(fs, parent);
2930                 if (err) {
2931                         ret = translate_error(fs, parent, err);
2932                         goto out2;
2933                 }
2934
2935                 err = ext2fs_link(fs, parent, node_name, child,
2936                                      filetype);
2937         }
2938         if (err) {
2939                 ret = translate_error(fs, parent, err);
2940                 goto out2;
2941         }
2942
2943         ret = update_mtime(fs, parent, NULL);
2944         if (ret)
2945                 goto out2;
2946
2947         memset(&inode, 0, sizeof(inode));
2948         inode.i_mode = mode;
2949         inode.i_links_count = 1;
2950         inode.i_extra_isize = sizeof(struct ext2_inode_large) -
2951                 EXT2_GOOD_OLD_INODE_SIZE;
2952         inode.i_uid = ctxt->uid;
2953         ext2fs_set_i_uid_high(inode, ctxt->uid >> 16);
2954         inode.i_gid = ctxt->gid;
2955         ext2fs_set_i_gid_high(inode, ctxt->gid >> 16);
2956         if (ext2fs_has_feature_extents(fs->super)) {
2957                 ext2_extent_handle_t handle;
2958
2959                 inode.i_flags &= ~EXT4_EXTENTS_FL;
2960                 ret = ext2fs_extent_open2(fs, child,
2961                                           (struct ext2_inode *)&inode, &handle);
2962                 if (ret)
2963                         return ret;
2964                 ext2fs_extent_free(handle);
2965         }
2966
2967         err = ext2fs_write_new_inode(fs, child, (struct ext2_inode *)&inode);
2968         if (err) {
2969                 ret = translate_error(fs, child, err);
2970                 goto out2;
2971         }
2972
2973         inode.i_generation = ff->next_generation++;
2974         init_times(&inode);
2975         err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode,
2976                                       sizeof(inode));
2977         if (err) {
2978                 ret = translate_error(fs, child, err);
2979                 goto out2;
2980         }
2981
2982         ext2fs_inode_alloc_stats2(fs, child, 1, 0);
2983
2984         ret = __op_open(ff, path, fp);
2985         if (ret)
2986                 goto out2;
2987 out2:
2988         pthread_mutex_unlock(&ff->bfl);
2989 out:
2990         free(temp_path);
2991         return ret;
2992 }
2993
2994 #if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
2995 static int op_ftruncate(const char *path EXT2FS_ATTR((unused)),
2996                         off_t len, struct fuse_file_info *fp)
2997 {
2998         struct fuse_context *ctxt = fuse_get_context();
2999         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3000         struct fuse2fs_file_handle *fh =
3001                 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
3002         ext2_filsys fs;
3003         ext2_file_t efp;
3004         errcode_t err;
3005         int ret = 0;
3006
3007         FUSE2FS_CHECK_CONTEXT(ff);
3008         fs = ff->fs;
3009         FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3010         dbg_printf("%s: ino=%d len=%jd\n", __func__, fh->ino, len);
3011         pthread_mutex_lock(&ff->bfl);
3012         if (!fs_writeable(fs)) {
3013                 ret = -EROFS;
3014                 goto out;
3015         }
3016
3017         err = ext2fs_file_open(fs, fh->ino, fh->open_flags, &efp);
3018         if (err) {
3019                 ret = translate_error(fs, fh->ino, err);
3020                 goto out;
3021         }
3022
3023         err = ext2fs_file_set_size2(efp, len);
3024         if (err) {
3025                 ret = translate_error(fs, fh->ino, err);
3026                 goto out2;
3027         }
3028
3029 out2:
3030         err = ext2fs_file_close(efp);
3031         if (ret)
3032                 goto out;
3033         if (err) {
3034                 ret = translate_error(fs, fh->ino, err);
3035                 goto out;
3036         }
3037
3038         ret = update_mtime(fs, fh->ino, NULL);
3039         if (ret)
3040                 goto out;
3041
3042 out:
3043         pthread_mutex_unlock(&ff->bfl);
3044         return 0;
3045 }
3046
3047 static int op_fgetattr(const char *path EXT2FS_ATTR((unused)),
3048                        struct stat *statbuf,
3049                        struct fuse_file_info *fp)
3050 {
3051         struct fuse_context *ctxt = fuse_get_context();
3052         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3053         ext2_filsys fs;
3054         struct fuse2fs_file_handle *fh =
3055                 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
3056         int ret = 0;
3057
3058         FUSE2FS_CHECK_CONTEXT(ff);
3059         fs = ff->fs;
3060         FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3061         dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3062         pthread_mutex_lock(&ff->bfl);
3063         ret = stat_inode(fs, fh->ino, statbuf);
3064         pthread_mutex_unlock(&ff->bfl);
3065
3066         return ret;
3067 }
3068 #endif /* FUSE_VERSION < FUSE_MAKE_VERSION(3, 0) */
3069
3070 static int op_utimens(const char *path, const struct timespec ctv[2]
3071 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
3072                         , struct fuse_file_info *fi EXT2FS_ATTR((unused))
3073 #endif
3074                         )
3075 {
3076         struct fuse_context *ctxt = fuse_get_context();
3077         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3078         struct timespec tv[2];
3079         ext2_filsys fs;
3080         errcode_t err;
3081         ext2_ino_t ino;
3082         struct ext2_inode_large inode;
3083         int ret = 0;
3084
3085         FUSE2FS_CHECK_CONTEXT(ff);
3086         fs = ff->fs;
3087         pthread_mutex_lock(&ff->bfl);
3088         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
3089         if (err) {
3090                 ret = translate_error(fs, 0, err);
3091                 goto out;
3092         }
3093         dbg_printf("%s: ino=%d\n", __func__, ino);
3094
3095         ret = check_inum_access(fs, ino, W_OK);
3096         if (ret)
3097                 goto out;
3098
3099         memset(&inode, 0, sizeof(inode));
3100         err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
3101                                      sizeof(inode));
3102         if (err) {
3103                 ret = translate_error(fs, ino, err);
3104                 goto out;
3105         }
3106
3107         tv[0] = ctv[0];
3108         tv[1] = ctv[1];
3109 #ifdef UTIME_NOW
3110         if (tv[0].tv_nsec == UTIME_NOW)
3111                 get_now(tv);
3112         if (tv[1].tv_nsec == UTIME_NOW)
3113                 get_now(tv + 1);
3114 #endif /* UTIME_NOW */
3115 #ifdef UTIME_OMIT
3116         if (tv[0].tv_nsec != UTIME_OMIT)
3117                 EXT4_INODE_SET_XTIME(i_atime, tv, &inode);
3118         if (tv[1].tv_nsec != UTIME_OMIT)
3119                 EXT4_INODE_SET_XTIME(i_mtime, tv + 1, &inode);
3120 #endif /* UTIME_OMIT */
3121         ret = update_ctime(fs, ino, &inode);
3122         if (ret)
3123                 goto out;
3124
3125         err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
3126                                       sizeof(inode));
3127         if (err) {
3128                 ret = translate_error(fs, ino, err);
3129                 goto out;
3130         }
3131
3132 out:
3133         pthread_mutex_unlock(&ff->bfl);
3134         return ret;
3135 }
3136
3137 #ifdef SUPPORT_I_FLAGS
3138 static int ioctl_getflags(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3139                           void *data)
3140 {
3141         errcode_t err;
3142         struct ext2_inode_large inode;
3143
3144         FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3145         dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3146         memset(&inode, 0, sizeof(inode));
3147         err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3148                                      sizeof(inode));
3149         if (err)
3150                 return translate_error(fs, fh->ino, err);
3151
3152         *(__u32 *)data = inode.i_flags & EXT2_FL_USER_VISIBLE;
3153         return 0;
3154 }
3155
3156 #define FUSE2FS_MODIFIABLE_IFLAGS \
3157         (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL | EXT2_NODUMP_FL | \
3158          EXT2_NOATIME_FL | EXT3_JOURNAL_DATA_FL | EXT2_DIRSYNC_FL | \
3159          EXT2_TOPDIR_FL)
3160
3161 static int ioctl_setflags(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3162                           void *data)
3163 {
3164         errcode_t err;
3165         struct ext2_inode_large inode;
3166         int ret;
3167         __u32 flags = *(__u32 *)data;
3168         struct fuse_context *ctxt = fuse_get_context();
3169         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3170
3171         FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3172         dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3173         memset(&inode, 0, sizeof(inode));
3174         err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3175                                      sizeof(inode));
3176         if (err)
3177                 return translate_error(fs, fh->ino, err);
3178
3179         if (!ff->fakeroot && ctxt->uid != 0 && inode_uid(inode) != ctxt->uid)
3180                 return -EPERM;
3181
3182         if ((inode.i_flags ^ flags) & ~FUSE2FS_MODIFIABLE_IFLAGS)
3183                 return -EINVAL;
3184
3185         inode.i_flags = (inode.i_flags & ~FUSE2FS_MODIFIABLE_IFLAGS) |
3186                         (flags & FUSE2FS_MODIFIABLE_IFLAGS);
3187
3188         ret = update_ctime(fs, fh->ino, &inode);
3189         if (ret)
3190                 return ret;
3191
3192         err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3193                                       sizeof(inode));
3194         if (err)
3195                 return translate_error(fs, fh->ino, err);
3196
3197         return 0;
3198 }
3199
3200 static int ioctl_getversion(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3201                             void *data)
3202 {
3203         errcode_t err;
3204         struct ext2_inode_large inode;
3205
3206         FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3207         dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3208         memset(&inode, 0, sizeof(inode));
3209         err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3210                                      sizeof(inode));
3211         if (err)
3212                 return translate_error(fs, fh->ino, err);
3213
3214         *(__u32 *)data = inode.i_generation;
3215         return 0;
3216 }
3217
3218 static int ioctl_setversion(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3219                             void *data)
3220 {
3221         errcode_t err;
3222         struct ext2_inode_large inode;
3223         int ret;
3224         __u32 generation = *(__u32 *)data;
3225         struct fuse_context *ctxt = fuse_get_context();
3226         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3227
3228         FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3229         dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3230         memset(&inode, 0, sizeof(inode));
3231         err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3232                                      sizeof(inode));
3233         if (err)
3234                 return translate_error(fs, fh->ino, err);
3235
3236         if (!ff->fakeroot && ctxt->uid != 0 && inode_uid(inode) != ctxt->uid)
3237                 return -EPERM;
3238
3239         inode.i_generation = generation;
3240
3241         ret = update_ctime(fs, fh->ino, &inode);
3242         if (ret)
3243                 return ret;
3244
3245         err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3246                                       sizeof(inode));
3247         if (err)
3248                 return translate_error(fs, fh->ino, err);
3249
3250         return 0;
3251 }
3252 #endif /* SUPPORT_I_FLAGS */
3253
3254 #ifdef FITRIM
3255 static int ioctl_fitrim(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3256                         void *data)
3257 {
3258         struct fstrim_range *fr = data;
3259         blk64_t start, end, max_blocks, b, cleared;
3260         errcode_t err = 0;
3261
3262         start = fr->start / fs->blocksize;
3263         end = (fr->start + fr->len - 1) / fs->blocksize;
3264         dbg_printf("%s: start=%llu end=%llu\n", __func__, start, end);
3265
3266         if (start < fs->super->s_first_data_block)
3267                 start = fs->super->s_first_data_block;
3268         if (start >= ext2fs_blocks_count(fs->super))
3269                 start = ext2fs_blocks_count(fs->super) - 1;
3270
3271         if (end < fs->super->s_first_data_block)
3272                 end = fs->super->s_first_data_block;
3273         if (end >= ext2fs_blocks_count(fs->super))
3274                 end = ext2fs_blocks_count(fs->super) - 1;
3275
3276         cleared = 0;
3277         max_blocks = 2048ULL * 1024 * 1024 / fs->blocksize;
3278
3279         fr->len = 0;
3280         while (start <= end) {
3281                 err = ext2fs_find_first_zero_block_bitmap2(fs->block_map,
3282                                                            start, end, &start);
3283                 if (err == ENOENT)
3284                         return 0;
3285                 else if (err)
3286                         return translate_error(fs, fh->ino, err);
3287
3288                 b = start + max_blocks < end ? start + max_blocks : end;
3289                 err =  ext2fs_find_first_set_block_bitmap2(fs->block_map,
3290                                                            start, b, &b);
3291                 if (err && err != ENOENT)
3292                         return translate_error(fs, fh->ino, err);
3293                 if (b - start >= fr->minlen) {
3294                         err = io_channel_discard(fs->io, start, b - start);
3295                         if (err)
3296                                 return translate_error(fs, fh->ino, err);
3297                         cleared += b - start;
3298                         fr->len = cleared * fs->blocksize;
3299                 }
3300                 start = b + 1;
3301         }
3302
3303         return err;
3304 }
3305 #endif /* FITRIM */
3306
3307 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
3308 static int op_ioctl(const char *path EXT2FS_ATTR((unused)),
3309 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
3310                     unsigned int cmd,
3311 #else
3312                     int cmd,
3313 #endif
3314                     void *arg EXT2FS_ATTR((unused)),
3315                     struct fuse_file_info *fp,
3316                     unsigned int flags EXT2FS_ATTR((unused)), void *data)
3317 {
3318         struct fuse_context *ctxt = fuse_get_context();
3319         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3320         struct fuse2fs_file_handle *fh =
3321                 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
3322         ext2_filsys fs;
3323         int ret = 0;
3324
3325         FUSE2FS_CHECK_CONTEXT(ff);
3326         fs = ff->fs;
3327         pthread_mutex_lock(&ff->bfl);
3328         switch ((unsigned long) cmd) {
3329 #ifdef SUPPORT_I_FLAGS
3330         case EXT2_IOC_GETFLAGS:
3331                 ret = ioctl_getflags(fs, fh, data);
3332                 break;
3333         case EXT2_IOC_SETFLAGS:
3334                 ret = ioctl_setflags(fs, fh, data);
3335                 break;
3336         case EXT2_IOC_GETVERSION:
3337                 ret = ioctl_getversion(fs, fh, data);
3338                 break;
3339         case EXT2_IOC_SETVERSION:
3340                 ret = ioctl_setversion(fs, fh, data);
3341                 break;
3342 #endif
3343 #ifdef FITRIM
3344         case FITRIM:
3345                 ret = ioctl_fitrim(fs, fh, data);
3346                 break;
3347 #endif
3348         default:
3349                 dbg_printf("%s: Unknown ioctl %d\n", __func__, cmd);
3350                 ret = -ENOTTY;
3351         }
3352         pthread_mutex_unlock(&ff->bfl);
3353
3354         return ret;
3355 }
3356 #endif /* FUSE 28 */
3357
3358 static int op_bmap(const char *path, size_t blocksize EXT2FS_ATTR((unused)),
3359                    uint64_t *idx)
3360 {
3361         struct fuse_context *ctxt = fuse_get_context();
3362         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3363         ext2_filsys fs;
3364         ext2_ino_t ino;
3365         errcode_t err;
3366         int ret = 0;
3367
3368         FUSE2FS_CHECK_CONTEXT(ff);
3369         fs = ff->fs;
3370         pthread_mutex_lock(&ff->bfl);
3371         err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
3372         if (err) {
3373                 ret = translate_error(fs, 0, err);
3374                 goto out;
3375         }
3376         dbg_printf("%s: ino=%d blk=%"PRIu64"\n", __func__, ino, *idx);
3377
3378         err = ext2fs_bmap2(fs, ino, NULL, NULL, 0, *idx, 0, (blk64_t *)idx);
3379         if (err) {
3380                 ret = translate_error(fs, ino, err);
3381                 goto out;
3382         }
3383
3384 out:
3385         pthread_mutex_unlock(&ff->bfl);
3386         return ret;
3387 }
3388
3389 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
3390 # ifdef SUPPORT_FALLOCATE
3391 static int fallocate_helper(struct fuse_file_info *fp, int mode, off_t offset,
3392                             off_t len)
3393 {
3394         struct fuse_context *ctxt = fuse_get_context();
3395         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3396         struct fuse2fs_file_handle *fh =
3397                 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
3398         ext2_filsys fs;
3399         struct ext2_inode_large inode;
3400         blk64_t start, end;
3401         __u64 fsize;
3402         errcode_t err;
3403         int flags;
3404
3405         FUSE2FS_CHECK_CONTEXT(ff);
3406         fs = ff->fs;
3407         FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3408         start = offset / fs->blocksize;
3409         end = (offset + len - 1) / fs->blocksize;
3410         dbg_printf("%s: ino=%d mode=0x%x start=%jd end=%llu\n", __func__,
3411                    fh->ino, mode, offset / fs->blocksize, end);
3412         if (!fs_can_allocate(ff, len / fs->blocksize))
3413                 return -ENOSPC;
3414
3415         memset(&inode, 0, sizeof(inode));
3416         err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3417                                      sizeof(inode));
3418         if (err)
3419                 return err;
3420         fsize = EXT2_I_SIZE(&inode);
3421
3422         /* Allocate a bunch of blocks */
3423         flags = (mode & FL_KEEP_SIZE_FLAG ? 0 :
3424                         EXT2_FALLOCATE_INIT_BEYOND_EOF);
3425         err = ext2fs_fallocate(fs, flags, fh->ino,
3426                                (struct ext2_inode *)&inode,
3427                                ~0ULL, start, end - start + 1);
3428         if (err && err != EXT2_ET_BLOCK_ALLOC_FAIL)
3429                 return translate_error(fs, fh->ino, err);
3430
3431         /* Update i_size */
3432         if (!(mode & FL_KEEP_SIZE_FLAG)) {
3433                 if ((__u64) offset + len > fsize) {
3434                         err = ext2fs_inode_size_set(fs,
3435                                                 (struct ext2_inode *)&inode,
3436                                                 offset + len);
3437                         if (err)
3438                                 return translate_error(fs, fh->ino, err);
3439                 }
3440         }
3441
3442         err = update_mtime(fs, fh->ino, &inode);
3443         if (err)
3444                 return err;
3445
3446         err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3447                                       sizeof(inode));
3448         if (err)
3449                 return translate_error(fs, fh->ino, err);
3450
3451         return err;
3452 }
3453
3454 static errcode_t clean_block_middle(ext2_filsys fs, ext2_ino_t ino,
3455                                   struct ext2_inode_large *inode, off_t offset,
3456                                   off_t len, char **buf)
3457 {
3458         blk64_t blk;
3459         off_t residue;
3460         int retflags;
3461         errcode_t err;
3462
3463         residue = offset % fs->blocksize;
3464         if (residue == 0)
3465                 return 0;
3466
3467         if (!*buf) {
3468                 err = ext2fs_get_mem(fs->blocksize, buf);
3469                 if (err)
3470                         return err;
3471         }
3472
3473         err = ext2fs_bmap2(fs, ino, (struct ext2_inode *)inode, *buf, 0,
3474                            offset / fs->blocksize, &retflags, &blk);
3475         if (err)
3476                 return err;
3477         if (!blk || (retflags & BMAP_RET_UNINIT))
3478                 return 0;
3479
3480         err = io_channel_read_blk(fs->io, blk, 1, *buf);
3481         if (err)
3482                 return err;
3483
3484         memset(*buf + residue, 0, len);
3485
3486         return io_channel_write_blk(fs->io, blk, 1, *buf);
3487 }
3488
3489 static errcode_t clean_block_edge(ext2_filsys fs, ext2_ino_t ino,
3490                                   struct ext2_inode_large *inode, off_t offset,
3491                                   int clean_before, char **buf)
3492 {
3493         blk64_t blk;
3494         int retflags;
3495         off_t residue;
3496         errcode_t err;
3497
3498         residue = offset % fs->blocksize;
3499         if (residue == 0)
3500                 return 0;
3501
3502         if (!*buf) {
3503                 err = ext2fs_get_mem(fs->blocksize, buf);
3504                 if (err)
3505                         return err;
3506         }
3507
3508         err = ext2fs_bmap2(fs, ino, (struct ext2_inode *)inode, *buf, 0,
3509                            offset / fs->blocksize, &retflags, &blk);
3510         if (err)
3511                 return err;
3512
3513         err = io_channel_read_blk(fs->io, blk, 1, *buf);
3514         if (err)
3515                 return err;
3516         if (!blk || (retflags & BMAP_RET_UNINIT))
3517                 return 0;
3518
3519         if (clean_before)
3520                 memset(*buf, 0, residue);
3521         else
3522                 memset(*buf + residue, 0, fs->blocksize - residue);
3523
3524         return io_channel_write_blk(fs->io, blk, 1, *buf);
3525 }
3526
3527 static int punch_helper(struct fuse_file_info *fp, int mode, off_t offset,
3528                         off_t len)
3529 {
3530         struct fuse_context *ctxt = fuse_get_context();
3531         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3532         struct fuse2fs_file_handle *fh =
3533                 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
3534         ext2_filsys fs;
3535         struct ext2_inode_large inode;
3536         blk64_t start, end;
3537         errcode_t err;
3538         char *buf = NULL;
3539
3540         FUSE2FS_CHECK_CONTEXT(ff);
3541         fs = ff->fs;
3542         FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3543         dbg_printf("%s: offset=%jd len=%jd\n", __func__, offset, len);
3544
3545         /* kernel ext4 punch requires this flag to be set */
3546         if (!(mode & FL_KEEP_SIZE_FLAG))
3547                 return -EINVAL;
3548
3549         /* Punch out a bunch of blocks */
3550         start = (offset + fs->blocksize - 1) / fs->blocksize;
3551         end = (offset + len - fs->blocksize) / fs->blocksize;
3552         dbg_printf("%s: ino=%d mode=0x%x start=%llu end=%llu\n", __func__,
3553                    fh->ino, mode, start, end);
3554
3555         memset(&inode, 0, sizeof(inode));
3556         err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3557                                      sizeof(inode));
3558         if (err)
3559                 return translate_error(fs, fh->ino, err);
3560
3561         /* Zero everything before the first block and after the last block */
3562         if ((offset / fs->blocksize) == ((offset + len) / fs->blocksize))
3563                 err = clean_block_middle(fs, fh->ino, &inode, offset,
3564                                          len, &buf);
3565         else {
3566                 err = clean_block_edge(fs, fh->ino, &inode, offset, 0, &buf);
3567                 if (!err)
3568                         err = clean_block_edge(fs, fh->ino, &inode,
3569                                                offset + len, 1, &buf);
3570         }
3571         if (buf)
3572                 ext2fs_free_mem(&buf);
3573         if (err)
3574                 return translate_error(fs, fh->ino, err);
3575
3576         /* Unmap full blocks in the middle */
3577         if (start <= end) {
3578                 err = ext2fs_punch(fs, fh->ino, (struct ext2_inode *)&inode,
3579                                    NULL, start, end);
3580                 if (err)
3581                         return translate_error(fs, fh->ino, err);
3582         }
3583
3584         err = update_mtime(fs, fh->ino, &inode);
3585         if (err)
3586                 return err;
3587
3588         err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3589                                       sizeof(inode));
3590         if (err)
3591                 return translate_error(fs, fh->ino, err);
3592
3593         return 0;
3594 }
3595
3596 static int op_fallocate(const char *path EXT2FS_ATTR((unused)), int mode,
3597                         off_t offset, off_t len,
3598                         struct fuse_file_info *fp)
3599 {
3600         struct fuse_context *ctxt = fuse_get_context();
3601         struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3602         ext2_filsys fs = ff->fs;
3603         int ret;
3604
3605         /* Catch unknown flags */
3606         if (mode & ~(FL_PUNCH_HOLE_FLAG | FL_KEEP_SIZE_FLAG))
3607                 return -EINVAL;
3608
3609         pthread_mutex_lock(&ff->bfl);
3610         if (!fs_writeable(fs)) {
3611                 ret = -EROFS;
3612                 goto out;
3613         }
3614         if (mode & FL_PUNCH_HOLE_FLAG)
3615                 ret = punch_helper(fp, mode, offset, len);
3616         else
3617                 ret = fallocate_helper(fp, mode, offset, len);
3618 out:
3619         pthread_mutex_unlock(&ff->bfl);
3620
3621         return ret;
3622 }
3623 # endif /* SUPPORT_FALLOCATE */
3624 #endif /* FUSE 29 */
3625
3626 static struct fuse_operations fs_ops = {
3627         .init = op_init,
3628         .destroy = op_destroy,
3629         .getattr = op_getattr,
3630         .readlink = op_readlink,
3631         .mknod = op_mknod,
3632         .mkdir = op_mkdir,
3633         .unlink = op_unlink,
3634         .rmdir = op_rmdir,
3635         .symlink = op_symlink,
3636         .rename = op_rename,
3637         .link = op_link,
3638         .chmod = op_chmod,
3639         .chown = op_chown,
3640         .truncate = op_truncate,
3641         .open = op_open,
3642         .read = op_read,
3643         .write = op_write,
3644         .statfs = op_statfs,
3645         .release = op_release,
3646         .fsync = op_fsync,
3647         .setxattr = op_setxattr,
3648         .getxattr = op_getxattr,
3649         .listxattr = op_listxattr,
3650         .removexattr = op_removexattr,
3651         .opendir = op_open,
3652         .readdir = op_readdir,
3653         .releasedir = op_release,
3654         .fsyncdir = op_fsync,
3655         .access = op_access,
3656         .create = op_create,
3657 #if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
3658         .ftruncate = op_ftruncate,
3659         .fgetattr = op_fgetattr,
3660 #endif
3661         .utimens = op_utimens,
3662 #if (FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)) && (FUSE_VERSION < FUSE_MAKE_VERSION(3, 0))
3663 # if defined(UTIME_NOW) || defined(UTIME_OMIT)
3664         .flag_utime_omit_ok = 1,
3665 # endif
3666 #endif
3667         .bmap = op_bmap,
3668 #ifdef SUPERFLUOUS
3669         .lock = op_lock,
3670         .poll = op_poll,
3671 #endif
3672 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
3673         .ioctl = op_ioctl,
3674 #if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
3675         .flag_nullpath_ok = 1,
3676 #endif
3677 #endif
3678 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
3679 #if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
3680         .flag_nopath = 1,
3681 #endif
3682 # ifdef SUPPORT_FALLOCATE
3683         .fallocate = op_fallocate,
3684 # endif
3685 #endif
3686 };
3687
3688 static int get_random_bytes(void *p, size_t sz)
3689 {
3690         int fd;
3691         ssize_t r;
3692
3693         fd = open("/dev/urandom", O_RDONLY);
3694         if (fd < 0) {
3695                 perror("/dev/urandom");
3696                 return 0;
3697         }
3698
3699         r = read(fd, p, sz);
3700
3701         close(fd);
3702         return (size_t) r == sz;
3703 }
3704
3705 enum {
3706         FUSE2FS_VERSION,
3707         FUSE2FS_HELP,
3708         FUSE2FS_HELPFULL,
3709 };
3710
3711 #define FUSE2FS_OPT(t, p, v) { t, offsetof(struct fuse2fs, p), v }
3712
3713 static struct fuse_opt fuse2fs_opts[] = {
3714         FUSE2FS_OPT("ro",               ro,                     1),
3715         FUSE2FS_OPT("errors=panic",     panic_on_error,         1),
3716         FUSE2FS_OPT("minixdf",          minixdf,                1),
3717         FUSE2FS_OPT("fakeroot",         fakeroot,               1),
3718         FUSE2FS_OPT("fuse2fs_debug",    debug,                  1),
3719         FUSE2FS_OPT("no_default_opts",  no_default_opts,        1),
3720         FUSE2FS_OPT("norecovery",       norecovery,             1),
3721         FUSE2FS_OPT("offset=%lu",       offset,         0),
3722
3723         FUSE_OPT_KEY("-V",             FUSE2FS_VERSION),
3724         FUSE_OPT_KEY("--version",      FUSE2FS_VERSION),
3725         FUSE_OPT_KEY("-h",             FUSE2FS_HELP),
3726         FUSE_OPT_KEY("--help",         FUSE2FS_HELP),
3727         FUSE_OPT_KEY("--helpfull",     FUSE2FS_HELPFULL),
3728         FUSE_OPT_END
3729 };
3730
3731
3732 static int fuse2fs_opt_proc(void *data, const char *arg,
3733                             int key, struct fuse_args *outargs)
3734 {
3735         struct fuse2fs *ff = data;
3736
3737         switch (key) {
3738         case FUSE_OPT_KEY_NONOPT:
3739                 if (!ff->device) {
3740                         ff->device = strdup(arg);
3741                         return 0;
3742                 }
3743                 return 1;
3744         case FUSE2FS_HELP:
3745         case FUSE2FS_HELPFULL:
3746                 fprintf(stderr,
3747         "usage: %s device/image mountpoint [options]\n"
3748         "\n"
3749         "general options:\n"
3750         "    -o opt,[opt...]  mount options\n"
3751         "    -h   --help      print help\n"
3752         "    -V   --version   print version\n"
3753         "\n"
3754         "fuse2fs options:\n"
3755         "    -o ro                  read-only mount\n"
3756         "    -o errors=panic        dump core on error\n"
3757         "    -o minixdf             minix-style df\n"
3758         "    -o fakeroot            pretend to be root for permission checks\n"
3759         "    -o no_default_opts     do not include default fuse options\n"
3760         "    -o offset=<bytes>      similar to mount -o offset=<bytes>, mount the partition starting at <bytes>\n"
3761         "    -o norecovery          don't replay the journal (implies ro)\n"
3762         "    -o fuse2fs_debug       enable fuse2fs debugging\n"
3763         "\n",
3764                         outargs->argv[0]);
3765                 if (key == FUSE2FS_HELPFULL) {
3766                         fuse_opt_add_arg(outargs, "-ho");
3767                         fuse_main(outargs->argc, outargs->argv, &fs_ops, NULL);
3768                 } else {
3769                         fprintf(stderr, "Try --helpfull to get a list of "
3770                                 "all flags, including the FUSE options.\n");
3771                 }
3772                 exit(1);
3773
3774         case FUSE2FS_VERSION:
3775                 fprintf(stderr, "fuse2fs %s (%s)\n", E2FSPROGS_VERSION,
3776                         E2FSPROGS_DATE);
3777                 fuse_opt_add_arg(outargs, "--version");
3778                 fuse_main(outargs->argc, outargs->argv, &fs_ops, NULL);
3779                 exit(0);
3780         }
3781         return 1;
3782 }
3783
3784 int main(int argc, char *argv[])
3785 {
3786         struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
3787         struct fuse2fs fctx;
3788         errcode_t err;
3789         char *logfile;
3790         char extra_args[BUFSIZ];
3791         int ret = 0;
3792         int flags = EXT2_FLAG_64BITS | EXT2_FLAG_THREADS | EXT2_FLAG_EXCLUSIVE;
3793
3794         memset(&fctx, 0, sizeof(fctx));
3795         fctx.magic = FUSE2FS_MAGIC;
3796
3797         fuse_opt_parse(&args, &fctx, fuse2fs_opts, fuse2fs_opt_proc);
3798         if (fctx.device == NULL) {
3799                 fprintf(stderr, "Missing ext4 device/image\n");
3800                 fprintf(stderr, "See '%s -h' for usage\n", argv[0]);
3801                 exit(1);
3802         }
3803
3804         if (fctx.norecovery)
3805                 fctx.ro = 1;
3806         if (fctx.ro)
3807                 printf("%s", _("Mounting read-only.\n"));
3808
3809 #ifdef ENABLE_NLS
3810         setlocale(LC_MESSAGES, "");
3811         setlocale(LC_CTYPE, "");
3812         bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
3813         textdomain(NLS_CAT_NAME);
3814         set_com_err_gettext(gettext);
3815 #endif
3816         add_error_table(&et_ext2_error_table);
3817
3818         /* Set up error logging */
3819         logfile = getenv("FUSE2FS_LOGFILE");
3820         if (logfile) {
3821                 fctx.err_fp = fopen(logfile, "a");
3822                 if (!fctx.err_fp) {
3823                         perror(logfile);
3824                         goto out;
3825                 }
3826         } else
3827                 fctx.err_fp = stderr;
3828
3829         /* Will we allow users to allocate every last block? */
3830         if (getenv("FUSE2FS_ALLOC_ALL_BLOCKS")) {
3831                 printf(_("%s: Allowing users to allocate all blocks. "
3832                        "This is dangerous!\n"), fctx.device);
3833                 fctx.alloc_all_blocks = 1;
3834         }
3835
3836         /* Start up the fs (while we still can use stdout) */
3837         ret = 2;
3838         if (!fctx.ro)
3839                 flags |= EXT2_FLAG_RW;
3840         char options[50];
3841         sprintf(options, "offset=%lu", fctx.offset);
3842         err = ext2fs_open2(fctx.device, options, flags, 0, 0, unix_io_manager,
3843                            &global_fs);
3844         if (err) {
3845                 printf(_("%s: %s.\n"), fctx.device, error_message(err));
3846                 printf(_("Please run e2fsck -fy %s.\n"), fctx.device);
3847                 goto out;
3848         }
3849         fctx.fs = global_fs;
3850         global_fs->priv_data = &fctx;
3851
3852         ret = 3;
3853
3854         if (ext2fs_has_feature_journal_needs_recovery(global_fs->super)) {
3855                 if (fctx.norecovery) {
3856                         printf(_("%s: mounting read-only without "
3857                                  "recovering journal\n"),
3858                                fctx.device);
3859                 } else if (!fctx.ro) {
3860                         printf(_("%s: recovering journal\n"), fctx.device);
3861                         err = ext2fs_run_ext3_journal(&global_fs);
3862                         if (err) {
3863                                 printf(_("%s: %s.\n"), fctx.device,
3864                                        error_message(err));
3865                                 printf(_("Please run e2fsck -fy %s.\n"),
3866                                        fctx.device);
3867                                 goto out;
3868                         }
3869                         ext2fs_clear_feature_journal_needs_recovery(global_fs->super);
3870                         ext2fs_mark_super_dirty(global_fs);
3871                 } else {
3872                         printf("%s", _("Journal needs recovery; running "
3873                                "`e2fsck -E journal_only' is required.\n"));
3874                         goto out;
3875                 }
3876         }
3877
3878         if (!fctx.ro) {
3879                 if (ext2fs_has_feature_journal(global_fs->super))
3880                         printf(_("%s: Writing to the journal is not supported.\n"),
3881                                fctx.device);
3882                 err = ext2fs_read_inode_bitmap(global_fs);
3883                 if (err) {
3884                         translate_error(global_fs, 0, err);
3885                         goto out;
3886                 }
3887                 err = ext2fs_read_block_bitmap(global_fs);
3888                 if (err) {
3889                         translate_error(global_fs, 0, err);
3890                         goto out;
3891                 }
3892         }
3893
3894         if (!(global_fs->super->s_state & EXT2_VALID_FS))
3895                 printf("%s", _("Warning: Mounting unchecked fs, running e2fsck "
3896                        "is recommended.\n"));
3897         if (global_fs->super->s_max_mnt_count > 0 &&
3898             global_fs->super->s_mnt_count >= global_fs->super->s_max_mnt_count)
3899                 printf("%s", _("Warning: Maximal mount count reached, running "
3900                        "e2fsck is recommended.\n"));
3901         if (global_fs->super->s_checkinterval > 0 &&
3902             (time_t) (global_fs->super->s_lastcheck +
3903                       global_fs->super->s_checkinterval) <= time(0))
3904                 printf("%s", _("Warning: Check time reached; running e2fsck "
3905                        "is recommended.\n"));
3906         if (global_fs->super->s_last_orphan)
3907                 printf("%s",
3908                        _("Orphans detected; running e2fsck is recommended.\n"));
3909
3910         if (global_fs->super->s_state & EXT2_ERROR_FS) {
3911                 printf("%s",
3912                        _("Errors detected; running e2fsck is required.\n"));
3913                 goto out;
3914         }
3915
3916         /* Initialize generation counter */
3917         get_random_bytes(&fctx.next_generation, sizeof(unsigned int));
3918
3919         /* Set up default fuse parameters */
3920         snprintf(extra_args, BUFSIZ, "-okernel_cache,subtype=ext4,"
3921                  "fsname=%s,attr_timeout=0" FUSE_PLATFORM_OPTS,
3922                  fctx.device);
3923         if (fctx.no_default_opts == 0)
3924                 fuse_opt_add_arg(&args, extra_args);
3925
3926         if (fctx.fakeroot) {
3927 #ifdef HAVE_MOUNT_NODEV
3928                 fuse_opt_add_arg(&args,"-onodev");
3929 #endif
3930 #ifdef HAVE_MOUNT_NOSUID
3931                 fuse_opt_add_arg(&args,"-onosuid");
3932 #endif
3933         }
3934
3935         if (fctx.debug) {
3936                 int     i;
3937
3938                 printf("fuse arguments:");
3939                 for (i = 0; i < args.argc; i++)
3940                         printf(" '%s'", args.argv[i]);
3941                 printf("\n");
3942         }
3943
3944         pthread_mutex_init(&fctx.bfl, NULL);
3945         fuse_main(args.argc, args.argv, &fs_ops, &fctx);
3946         pthread_mutex_destroy(&fctx.bfl);
3947
3948         ret = 0;
3949 out:
3950         if (global_fs) {
3951                 err = ext2fs_close(global_fs);
3952                 if (err)
3953                         com_err(argv[0], err, "while closing fs");
3954                 global_fs = NULL;
3955         }
3956         return ret;
3957 }
3958
3959 static int __translate_error(ext2_filsys fs, errcode_t err, ext2_ino_t ino,
3960                              const char *file, int line)
3961 {
3962         struct timespec now;
3963         int ret = err;
3964         struct fuse2fs *ff = fs->priv_data;
3965         int is_err = 0;
3966
3967         /* Translate ext2 error to unix error code */
3968         if (err < EXT2_ET_BASE)
3969                 goto no_translation;
3970         switch (err) {
3971         case EXT2_ET_NO_MEMORY:
3972         case EXT2_ET_TDB_ERR_OOM:
3973                 ret = -ENOMEM;
3974                 break;
3975         case EXT2_ET_INVALID_ARGUMENT:
3976         case EXT2_ET_LLSEEK_FAILED:
3977                 ret = -EINVAL;
3978                 break;
3979         case EXT2_ET_NO_DIRECTORY:
3980                 ret = -ENOTDIR;
3981                 break;
3982         case EXT2_ET_FILE_NOT_FOUND:
3983                 ret = -ENOENT;
3984                 break;
3985         case EXT2_ET_DIR_NO_SPACE:
3986                 is_err = 1;
3987                 /* fallthrough */
3988         case EXT2_ET_TOOSMALL:
3989         case EXT2_ET_BLOCK_ALLOC_FAIL:
3990         case EXT2_ET_INODE_ALLOC_FAIL:
3991         case EXT2_ET_EA_NO_SPACE:
3992                 ret = -ENOSPC;
3993                 break;
3994         case EXT2_ET_SYMLINK_LOOP:
3995                 ret = -EMLINK;
3996                 break;
3997         case EXT2_ET_FILE_TOO_BIG:
3998                 ret = -EFBIG;
3999                 break;
4000         case EXT2_ET_TDB_ERR_EXISTS:
4001         case EXT2_ET_FILE_EXISTS:
4002                 ret = -EEXIST;
4003                 break;
4004         case EXT2_ET_MMP_FAILED:
4005         case EXT2_ET_MMP_FSCK_ON:
4006                 ret = -EBUSY;
4007                 break;
4008         case EXT2_ET_EA_KEY_NOT_FOUND:
4009 #ifdef ENODATA
4010                 ret = -ENODATA;
4011 #else
4012                 ret = -ENOENT;
4013 #endif
4014                 break;
4015         /* Sometimes fuse returns a garbage file handle pointer to us... */
4016         case EXT2_ET_MAGIC_EXT2_FILE:
4017                 ret = -EFAULT;
4018                 break;
4019         case EXT2_ET_UNIMPLEMENTED:
4020                 ret = -EOPNOTSUPP;
4021                 break;
4022         default:
4023                 is_err = 1;
4024                 ret = -EIO;
4025                 break;
4026         }
4027
4028 no_translation:
4029         if (!is_err)
4030                 return ret;
4031
4032         if (ino)
4033                 fprintf(ff->err_fp, "FUSE2FS (%s): %s (inode #%d) at %s:%d.\n",
4034                         fs->device_name ? fs->device_name : "???",
4035                         error_message(err), ino, file, line);
4036         else
4037                 fprintf(ff->err_fp, "FUSE2FS (%s): %s at %s:%d.\n",
4038                         fs->device_name ? fs->device_name : "???",
4039                         error_message(err), file, line);
4040         fflush(ff->err_fp);
4041
4042         /* Make a note in the error log */
4043         get_now(&now);
4044         ext2fs_set_tstamp(fs->super, s_last_error_time, now.tv_sec);
4045         fs->super->s_last_error_ino = ino;
4046         fs->super->s_last_error_line = line;
4047         fs->super->s_last_error_block = err; /* Yeah... */
4048         strncpy((char *)fs->super->s_last_error_func, file,
4049                 sizeof(fs->super->s_last_error_func));
4050         if (ext2fs_get_tstamp(fs->super, s_first_error_time) == 0) {
4051                 ext2fs_set_tstamp(fs->super, s_first_error_time, now.tv_sec);
4052                 fs->super->s_first_error_ino = ino;
4053                 fs->super->s_first_error_line = line;
4054                 fs->super->s_first_error_block = err;
4055                 strncpy((char *)fs->super->s_first_error_func, file,
4056                         sizeof(fs->super->s_first_error_func));
4057         }
4058
4059         fs->super->s_error_count++;
4060         ext2fs_mark_super_dirty(fs);
4061         ext2fs_flush(fs);
4062         if (ff->panic_on_error)
4063                 abort();
4064
4065         return ret;
4066 }