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