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