]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - misc/fuse2fs.c
Merge branch 'maint' into next
[thirdparty/e2fsprogs.git] / misc / fuse2fs.c
CommitLineData
81cbf1ef
DW
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
4e222d9b 13#ifndef _GNU_SOURCE
81cbf1ef 14#define _GNU_SOURCE
4e222d9b 15#endif
81cbf1ef
DW
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
69df8496
TT
39#include "../version.h"
40
81cbf1ef
DW
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
63static 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
96errcode_t ext2fs_run_ext3_journal(ext2_filsys *fs);
97
1fc23b5e
TT
98#ifdef CONFIG_JBD_DEBUG /* Enabled by configure --enable-jbd-debug */
99int journal_enable_debug = -1;
100#endif
101
81cbf1ef
DW
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
113typedef struct {
114 u_int16_t e_tag;
115 u_int16_t e_perm;
116 u_int32_t e_id;
117} acl_ea_entry;
118
119typedef struct {
120 u_int32_t a_version;
fddc423d 121#if __GNUC_PREREQ (4, 8)
ac3256fd
TT
122#pragma GCC diagnostic push
123#pragma GCC diagnostic ignored "-Wpedantic"
fddc423d 124#endif
81cbf1ef 125 acl_ea_entry a_entries[0];
fddc423d 126#if __GNUC_PREREQ (4, 8)
ac3256fd 127#pragma GCC diagnostic pop
fddc423d 128#endif
81cbf1ef
DW
129} acl_ea_header;
130
131static inline size_t acl_ea_size(int count)
132{
133 return sizeof(acl_ea_header) + count * sizeof(acl_ea_entry);
134}
135
136static 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
151typedef struct {
152 __u16 e_tag;
153 __u16 e_perm;
154 __u32 e_id;
155} ext4_acl_entry;
156
157typedef struct {
158 __u16 e_tag;
159 __u16 e_perm;
160} ext4_acl_entry_short;
161
162typedef struct {
163 __u32 a_version;
164} ext4_acl_header;
165
166static 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
178static 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
194static 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;
4e222d9b 202 unsigned char *hptr;
81cbf1ef
DW
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);
4e222d9b 215 hptr = (unsigned char *) (h + 1);
81cbf1ef 216 for (i = 0, a = facl->a_entries; i < facl_count; i++, a++) {
4e222d9b 217 e = (ext4_acl_entry *) hptr;
81cbf1ef
DW
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;
242out:
243 ext2fs_free_mem(&h);
244 return err;
245}
246
247static 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;
4e222d9b 255 unsigned char *hptr;
81cbf1ef
DW
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;
4e222d9b 269 hptr = (unsigned char *) (eacl + 1);
81cbf1ef 270 for (i = 0, a = f->a_entries; i < eacl_count; i++, a++) {
4e222d9b 271 e = (ext4_acl_entry *) hptr;
81cbf1ef
DW
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;
296out:
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)
307struct 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)
315struct fuse2fs {
316 unsigned long magic;
317 ext2_filsys fs;
318 pthread_mutex_t bfl;
69df8496
TT
319 char *device;
320 int ro;
321 int debug;
322 int no_default_opts;
81cbf1ef
DW
323 int panic_on_error;
324 int minixdf;
ea1a3fa2 325 int fakeroot;
81cbf1ef
DW
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
339static 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)) \
4e222d9b 370 <= ((size_t) EXT2_GOOD_OLD_INODE_SIZE + \
81cbf1ef
DW
371 (ext4_inode)->i_extra_isize)) \
372
373static 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
381static 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) \
397do { \
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) \
405do { \
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) \
414do { \
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) \
424do { \
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
435static 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
446static 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
459static 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
471static 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
505static 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
539static 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
573static 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
599static 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
626static int fs_writeable(ext2_filsys fs)
627{
628 return (fs->flags & EXT2_FLAG_RW) && (fs->super->s_error_count == 0);
629}
630
4e222d9b 631static int check_inum_access(ext2_filsys fs, ext2_ino_t ino, mode_t mask)
81cbf1ef
DW
632{
633 struct fuse_context *ctxt = fuse_get_context();
ea1a3fa2 634 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
81cbf1ef
DW
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 */
ea1a3fa2 664 if (ff->fakeroot || ctxt->uid == 0) {
81cbf1ef
DW
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
4e222d9b 701static void op_destroy(void *p EXT2FS_ATTR((unused)))
81cbf1ef
DW
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
729static 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
757static 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;
7889640d 763 if (ext2fs_has_feature_huge_file(fs->super))
81cbf1ef
DW
764 b += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32;
765
7889640d 766 if (!ext2fs_has_feature_huge_file(fs->super) ||
81cbf1ef
DW
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
774static 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
815static 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);
834out:
835 pthread_mutex_unlock(&ff->bfl);
836 return ret;
837}
838
839static 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;
cf0be234
TE
875 if (ext2fs_is_fast_symlink(&inode))
876 memcpy(buf, (char *)inode.i_block, len);
877 else {
81cbf1ef
DW
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
893out2:
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 }
cf0be234 901 }
81cbf1ef
DW
902 buf[len] = 0;
903
904 if (fs_writeable(fs)) {
905 ret = update_atime(fs, ino);
906 if (ret)
907 goto out;
908 }
909
910out:
911 pthread_mutex_unlock(&ff->bfl);
912 return ret;
913}
914
915static 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;
da9d5b80 921 char *temp_path;
81cbf1ef
DW
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);
da9d5b80 932 temp_path = strdup(path);
81cbf1ef
DW
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;
f150bdec
DW
1016 inode.i_uid = ctxt->uid;
1017 inode.i_gid = ctxt->gid;
81cbf1ef
DW
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
1036out2:
1037 pthread_mutex_unlock(&ff->bfl);
1038out:
1039 free(temp_path);
1040 return ret;
1041}
1042
1043static 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;
da9d5b80 1049 char *temp_path;
81cbf1ef
DW
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);
da9d5b80 1061 temp_path = strdup(path);
81cbf1ef
DW
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) ||
7889640d 1155 !ext2fs_has_feature_metadata_csum(fs->super))
81cbf1ef
DW
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
1174out3:
1175 ext2fs_free_mem(&block);
1176out2:
1177 pthread_mutex_unlock(&ff->bfl);
1178out:
1179 free(temp_path);
1180 return ret;
1181}
1182
1183static 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
1221static 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
1273write_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 }
1280out:
1281 return ret;
1282}
1283
1284static 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;
1304out:
1305 return ret;
1306}
1307
1308static 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
1321struct rd_struct {
1322 ext2_ino_t parent;
1323 int empty;
1324};
1325
1326static 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
1349static 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
1414out:
1415 return ret;
1416}
1417
1418static 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
1431static 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;
da9d5b80 1437 char *temp_path;
81cbf1ef
DW
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);
da9d5b80 1446 temp_path = strdup(dest);
81cbf1ef
DW
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 */
4e222d9b 1475 err = ext2fs_symlink(fs, parent, 0, node_name, src);
81cbf1ef
DW
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
4e222d9b 1483 err = ext2fs_symlink(fs, parent, 0, node_name, src);
81cbf1ef
DW
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 }
1523out2:
1524 pthread_mutex_unlock(&ff->bfl);
1525out:
1526 free(temp_path);
1527 return ret;
1528}
1529
1530struct update_dotdot {
1531 ext2_ino_t new_dotdot;
1532};
1533
4e222d9b
TT
1534static 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)
81cbf1ef
DW
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
1553static 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
1770out2:
1771 free(temp_from);
1772 free(temp_to);
1773out:
1774 pthread_mutex_unlock(&ff->bfl);
1775 return ret;
1776}
1777
1778static 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;
da9d5b80 1783 char *temp_path;
81cbf1ef
DW
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);
da9d5b80 1793 temp_path = strdup(dest);
81cbf1ef
DW
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
1875out2:
1876 pthread_mutex_unlock(&ff->bfl);
1877out:
1878 free(temp_path);
1879 return ret;
1880}
1881
1882static 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
ea1a3fa2 1910 if (!ff->fakeroot && ctxt->uid != 0 && ctxt->uid != inode.i_uid) {
81cbf1ef
DW
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 */
ea1a3fa2 1920 if (!ff->fakeroot && ctxt->uid != 0 && ctxt->gid != inode.i_gid)
81cbf1ef
DW
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
1936out:
1937 pthread_mutex_unlock(&ff->bfl);
1938 return ret;
1939}
1940
1941static 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" */
4e222d9b 1971 if (owner != (uid_t) ~0) {
81cbf1ef 1972 /* Only root gets to change UID. */
ea1a3fa2 1973 if (!ff->fakeroot && ctxt->uid != 0 &&
81cbf1ef
DW
1974 !(inode.i_uid == ctxt->uid && owner == ctxt->uid)) {
1975 ret = -EPERM;
1976 goto out;
1977 }
1978 inode.i_uid = owner;
1979 }
1980
4e222d9b 1981 if (group != (gid_t) ~0) {
81cbf1ef 1982 /* Only root or the owner get to change GID. */
ea1a3fa2 1983 if (!ff->fakeroot && ctxt->uid != 0 && inode.i_uid != ctxt->uid) {
81cbf1ef
DW
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
2003out:
2004 pthread_mutex_unlock(&ff->bfl);
2005 return ret;
2006}
2007
2008static 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
2044out2:
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
2055out:
2056 pthread_mutex_unlock(&ff->bfl);
2057 return err;
2058}
2059
2060#ifdef __linux__
2061static 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
2074static void detect_linux_executable_open(int kernel_flags, int *access_check,
2075 int *e2fs_open_flags)
2076{
2077 /* empty */
2078}
2079#endif /* __linux__ */
2080
2081static 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 }
377e3a96 2140 fp->fh = (uintptr_t)file;
81cbf1ef
DW
2141
2142out:
2143 if (ret)
2144 ext2fs_free_mem(&file);
2145 return ret;
2146}
2147
2148static 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
4e222d9b
TT
2161static int op_read(const char *path EXT2FS_ATTR((unused)), char *buf,
2162 size_t len, off_t offset,
2163 struct fuse_file_info *fp)
81cbf1ef
DW
2164{
2165 struct fuse_context *ctxt = fuse_get_context();
2166 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
377e3a96
TT
2167 struct fuse2fs_file_handle *fh =
2168 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
81cbf1ef
DW
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
2199out2:
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 }
2213out:
2214 pthread_mutex_unlock(&ff->bfl);
4e222d9b 2215 return got ? (int) got : ret;
81cbf1ef
DW
2216}
2217
4e222d9b
TT
2218static 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)
81cbf1ef
DW
2221{
2222 struct fuse_context *ctxt = fuse_get_context();
2223 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
377e3a96
TT
2224 struct fuse2fs_file_handle *fh =
2225 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
81cbf1ef
DW
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
2273out2:
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
2286out:
2287 pthread_mutex_unlock(&ff->bfl);
4e222d9b 2288 return got ? (int) got : ret;
81cbf1ef
DW
2289}
2290
4e222d9b
TT
2291static int op_release(const char *path EXT2FS_ATTR((unused)),
2292 struct fuse_file_info *fp)
81cbf1ef
DW
2293{
2294 struct fuse_context *ctxt = fuse_get_context();
2295 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
377e3a96
TT
2296 struct fuse2fs_file_handle *fh =
2297 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
81cbf1ef
DW
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
4e222d9b
TT
2320static int op_fsync(const char *path EXT2FS_ATTR((unused)),
2321 int datasync EXT2FS_ATTR((unused)),
2322 struct fuse_file_info *fp)
81cbf1ef
DW
2323{
2324 struct fuse_context *ctxt = fuse_get_context();
2325 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
377e3a96
TT
2326 struct fuse2fs_file_handle *fh =
2327 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
81cbf1ef
DW
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
4e222d9b
TT
2348static int op_statfs(const char *path EXT2FS_ATTR((unused)),
2349 struct statvfs *buf)
81cbf1ef
DW
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
2396typedef errcode_t (*xattr_xlate_get)(void **cooked_buf, size_t *cooked_sz,
2397 const void *raw_buf, size_t raw_sz);
2398typedef errcode_t (*xattr_xlate_set)(const void *cooked_buf, size_t cooked_sz,
4e222d9b 2399 const void **raw_buf, size_t *raw_sz);
81cbf1ef
DW
2400struct 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
2411static 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
2420static 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);
7889640d 2437 if (!ext2fs_has_feature_xattr(fs->super)) {
81cbf1ef
DW
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
2491out3:
2492 ext2fs_free_mem(&ptr);
2493out2:
2494 err = ext2fs_xattrs_close(&h);
2495 if (err)
2496 ret = translate_error(fs, ino, err);
2497out:
2498 pthread_mutex_unlock(&ff->bfl);
2499
2500 return ret;
2501}
2502
4e222d9b
TT
2503static int count_buffer_space(char *name, char *value EXT2FS_ATTR((unused)),
2504 size_t value_len EXT2FS_ATTR((unused)),
81cbf1ef
DW
2505 void *data)
2506{
2507 unsigned int *x = data;
2508
2509 *x = *x + strlen(name) + 1;
2510 return 0;
2511}
2512
4e222d9b
TT
2513static int copy_names(char *name, char *value EXT2FS_ATTR((unused)),
2514 size_t value_len EXT2FS_ATTR((unused)), void *data)
81cbf1ef
DW
2515{
2516 char **b = data;
2517
2518 strncpy(*b, name, strlen(name));
2519 *b = *b + strlen(name) + 1;
2520
2521 return 0;
2522}
2523
2524static int op_listxattr(const char *path, char *names, size_t len)
2525{
2526 struct fuse_context *ctxt = fuse_get_context();
2527 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2528 ext2_filsys fs;
2529 struct ext2_xattr_handle *h;
2530 unsigned int bufsz;
2531 ext2_ino_t ino;
2532 errcode_t err;
2533 int ret = 0;
2534
2535 FUSE2FS_CHECK_CONTEXT(ff);
2536 fs = ff->fs;
2537 pthread_mutex_lock(&ff->bfl);
7889640d 2538 if (!ext2fs_has_feature_xattr(fs->super)) {
81cbf1ef
DW
2539 ret = -ENOTSUP;
2540 goto out;
2541 }
2542
2543 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2544 if (err || ino == 0) {
2545 ret = translate_error(fs, ino, err);
2546 goto out;
2547 }
2548 dbg_printf("%s: ino=%d\n", __func__, ino);
2549
2550 ret = check_inum_access(fs, ino, R_OK);
2551 if (ret)
da9d5b80 2552 goto out;
81cbf1ef
DW
2553
2554 err = ext2fs_xattrs_open(fs, ino, &h);
2555 if (err) {
2556 ret = translate_error(fs, ino, err);
2557 goto out;
2558 }
2559
2560 err = ext2fs_xattrs_read(h);
2561 if (err) {
2562 ret = translate_error(fs, ino, err);
2563 goto out2;
2564 }
2565
2566 /* Count buffer space needed for names */
2567 bufsz = 0;
2568 err = ext2fs_xattrs_iterate(h, count_buffer_space, &bufsz);
2569 if (err) {
2570 ret = translate_error(fs, ino, err);
2571 goto out2;
2572 }
2573
2574 if (len == 0) {
2575 ret = bufsz;
2576 goto out2;
2577 } else if (len < bufsz) {
2578 ret = -ERANGE;
2579 goto out2;
2580 }
2581
2582 /* Copy names out */
2583 memset(names, 0, len);
2584 err = ext2fs_xattrs_iterate(h, copy_names, &names);
2585 if (err) {
2586 ret = translate_error(fs, ino, err);
2587 goto out2;
2588 }
2589 ret = bufsz;
2590out2:
2591 err = ext2fs_xattrs_close(&h);
2592 if (err)
2593 ret = translate_error(fs, ino, err);
2594out:
2595 pthread_mutex_unlock(&ff->bfl);
2596
2597 return ret;
2598}
2599
4e222d9b
TT
2600static int op_setxattr(const char *path EXT2FS_ATTR((unused)),
2601 const char *key, const char *value,
2602 size_t len, int flags EXT2FS_ATTR((unused)))
81cbf1ef
DW
2603{
2604 struct fuse_context *ctxt = fuse_get_context();
2605 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2606 ext2_filsys fs;
2607 struct ext2_xattr_handle *h;
2608 struct xattr_translate *xt;
4e222d9b 2609 const void *cvalue;
81cbf1ef
DW
2610 size_t clen;
2611 ext2_ino_t ino;
2612 errcode_t err;
2613 int ret = 0;
2614
2615 FUSE2FS_CHECK_CONTEXT(ff);
2616 fs = ff->fs;
2617 pthread_mutex_lock(&ff->bfl);
7889640d 2618 if (!ext2fs_has_feature_xattr(fs->super)) {
81cbf1ef
DW
2619 ret = -ENOTSUP;
2620 goto out;
2621 }
2622
2623 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2624 if (err || ino == 0) {
2625 ret = translate_error(fs, 0, err);
2626 goto out;
2627 }
2628 dbg_printf("%s: ino=%d\n", __func__, ino);
2629
2630 ret = check_inum_access(fs, ino, W_OK);
2631 if (ret == -EACCES) {
2632 ret = -EPERM;
2633 goto out;
2634 } else if (ret)
2635 goto out;
2636
2637 err = ext2fs_xattrs_open(fs, ino, &h);
2638 if (err) {
2639 ret = translate_error(fs, ino, err);
2640 goto out;
2641 }
2642
2643 err = ext2fs_xattrs_read(h);
2644 if (err) {
2645 ret = translate_error(fs, ino, err);
2646 goto out2;
2647 }
2648
4e222d9b 2649 cvalue = value;
81cbf1ef
DW
2650 clen = len;
2651 for (xt = xattr_translators; xt->prefix != NULL; xt++) {
2652 if (strncmp(key, xt->prefix, strlen(xt->prefix)) == 0) {
2653 err = xt->set(value, len, &cvalue, &clen);
2654 if (err)
2655 goto out3;
2656 }
2657 }
2658
2659 err = ext2fs_xattr_set(h, key, cvalue, clen);
2660 if (err) {
2661 ret = translate_error(fs, ino, err);
2662 goto out3;
2663 }
2664
81cbf1ef
DW
2665 ret = update_ctime(fs, ino, NULL);
2666out3:
2667 if (cvalue != value)
2668 ext2fs_free_mem(&cvalue);
2669out2:
2670 err = ext2fs_xattrs_close(&h);
2671 if (!ret && err)
2672 ret = translate_error(fs, ino, err);
2673out:
2674 pthread_mutex_unlock(&ff->bfl);
2675
2676 return ret;
2677}
2678
2679static int op_removexattr(const char *path, const char *key)
2680{
2681 struct fuse_context *ctxt = fuse_get_context();
2682 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2683 ext2_filsys fs;
2684 struct ext2_xattr_handle *h;
2685 ext2_ino_t ino;
2686 errcode_t err;
2687 int ret = 0;
2688
2689 FUSE2FS_CHECK_CONTEXT(ff);
2690 fs = ff->fs;
2691 pthread_mutex_lock(&ff->bfl);
7889640d 2692 if (!ext2fs_has_feature_xattr(fs->super)) {
81cbf1ef
DW
2693 ret = -ENOTSUP;
2694 goto out;
2695 }
2696
2697 if (!fs_can_allocate(ff, 1)) {
2698 ret = -ENOSPC;
2699 goto out;
2700 }
2701
2702 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2703 if (err || ino == 0) {
2704 ret = translate_error(fs, 0, err);
2705 goto out;
2706 }
2707 dbg_printf("%s: ino=%d\n", __func__, ino);
2708
2709 ret = check_inum_access(fs, ino, W_OK);
2710 if (ret)
2711 goto out;
2712
2713 err = ext2fs_xattrs_open(fs, ino, &h);
2714 if (err) {
2715 ret = translate_error(fs, ino, err);
2716 goto out;
2717 }
2718
2719 err = ext2fs_xattrs_read(h);
2720 if (err) {
2721 ret = translate_error(fs, ino, err);
2722 goto out2;
2723 }
2724
2725 err = ext2fs_xattr_remove(h, key);
2726 if (err) {
2727 ret = translate_error(fs, ino, err);
2728 goto out2;
2729 }
2730
81cbf1ef
DW
2731 ret = update_ctime(fs, ino, NULL);
2732out2:
2733 err = ext2fs_xattrs_close(&h);
2734 if (err)
2735 ret = translate_error(fs, ino, err);
2736out:
2737 pthread_mutex_unlock(&ff->bfl);
2738
2739 return ret;
2740}
2741
2742struct readdir_iter {
2743 void *buf;
2744 fuse_fill_dir_t func;
2745};
2746
4e222d9b
TT
2747static int op_readdir_iter(ext2_ino_t dir EXT2FS_ATTR((unused)),
2748 int entry EXT2FS_ATTR((unused)),
2749 struct ext2_dir_entry *dirent,
2750 int offset EXT2FS_ATTR((unused)),
2751 int blocksize EXT2FS_ATTR((unused)),
2752 char *buf EXT2FS_ATTR((unused)), void *data)
81cbf1ef
DW
2753{
2754 struct readdir_iter *i = data;
2755 char namebuf[EXT2_NAME_LEN + 1];
2756 int ret;
2757
2758 memcpy(namebuf, dirent->name, dirent->name_len & 0xFF);
2759 namebuf[dirent->name_len & 0xFF] = 0;
2760 ret = i->func(i->buf, namebuf, NULL, 0);
2761 if (ret)
2762 return DIRENT_ABORT;
2763
2764 return 0;
2765}
2766
4e222d9b
TT
2767static int op_readdir(const char *path EXT2FS_ATTR((unused)),
2768 void *buf, fuse_fill_dir_t fill_func,
2769 off_t offset EXT2FS_ATTR((unused)),
2770 struct fuse_file_info *fp)
81cbf1ef
DW
2771{
2772 struct fuse_context *ctxt = fuse_get_context();
2773 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
377e3a96
TT
2774 struct fuse2fs_file_handle *fh =
2775 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
81cbf1ef
DW
2776 ext2_filsys fs;
2777 errcode_t err;
2778 struct readdir_iter i;
2779 int ret = 0;
2780
2781 FUSE2FS_CHECK_CONTEXT(ff);
2782 fs = ff->fs;
2783 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2784 dbg_printf("%s: ino=%d\n", __func__, fh->ino);
2785 pthread_mutex_lock(&ff->bfl);
2786 i.buf = buf;
2787 i.func = fill_func;
2788 err = ext2fs_dir_iterate2(fs, fh->ino, 0, NULL, op_readdir_iter, &i);
2789 if (err) {
2790 ret = translate_error(fs, fh->ino, err);
2791 goto out;
2792 }
2793
2794 if (fs_writeable(fs)) {
2795 ret = update_atime(fs, fh->ino);
2796 if (ret)
2797 goto out;
2798 }
2799out:
2800 pthread_mutex_unlock(&ff->bfl);
2801 return ret;
2802}
2803
2804static int op_access(const char *path, int mask)
2805{
2806 struct fuse_context *ctxt = fuse_get_context();
2807 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2808 ext2_filsys fs;
2809 errcode_t err;
2810 ext2_ino_t ino;
2811 int ret = 0;
2812
2813 FUSE2FS_CHECK_CONTEXT(ff);
2814 fs = ff->fs;
2815 dbg_printf("%s: path=%s mask=0x%x\n", __func__, path, mask);
2816 pthread_mutex_lock(&ff->bfl);
2817 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2818 if (err || ino == 0) {
2819 ret = translate_error(fs, 0, err);
2820 goto out;
2821 }
2822
2823 ret = check_inum_access(fs, ino, mask);
2824 if (ret)
2825 goto out;
2826
2827out:
2828 pthread_mutex_unlock(&ff->bfl);
2829 return ret;
2830}
2831
2832static int op_create(const char *path, mode_t mode, struct fuse_file_info *fp)
2833{
2834 struct fuse_context *ctxt = fuse_get_context();
2835 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2836 ext2_filsys fs;
2837 ext2_ino_t parent, child;
da9d5b80 2838 char *temp_path;
81cbf1ef
DW
2839 errcode_t err;
2840 char *node_name, a;
2841 int filetype;
2842 struct ext2_inode_large inode;
2843 int ret = 0;
2844
2845 FUSE2FS_CHECK_CONTEXT(ff);
2846 fs = ff->fs;
2847 dbg_printf("%s: path=%s mode=0%o\n", __func__, path, mode);
da9d5b80 2848 temp_path = strdup(path);
81cbf1ef
DW
2849 if (!temp_path) {
2850 ret = -ENOMEM;
2851 goto out;
2852 }
2853 node_name = strrchr(temp_path, '/');
2854 if (!node_name) {
2855 ret = -ENOMEM;
2856 goto out;
2857 }
2858 node_name++;
2859 a = *node_name;
2860 *node_name = 0;
2861
2862 pthread_mutex_lock(&ff->bfl);
2863 if (!fs_can_allocate(ff, 1)) {
2864 ret = -ENOSPC;
2865 goto out2;
2866 }
2867
2868 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
2869 &parent);
2870 if (err) {
2871 ret = translate_error(fs, 0, err);
2872 goto out2;
2873 }
2874
2875 ret = check_inum_access(fs, parent, W_OK);
2876 if (ret)
2877 goto out2;
2878
2879 *node_name = a;
2880
2881 filetype = ext2_file_type(mode);
2882
2883 err = ext2fs_new_inode(fs, parent, mode, 0, &child);
2884 if (err) {
2885 ret = translate_error(fs, parent, err);
2886 goto out2;
2887 }
2888
2889 dbg_printf("%s: creating ino=%d/name=%s in dir=%d\n", __func__, child,
2890 node_name, parent);
2891 err = ext2fs_link(fs, parent, node_name, child, filetype);
2892 if (err == EXT2_ET_DIR_NO_SPACE) {
2893 err = ext2fs_expand_dir(fs, parent);
2894 if (err) {
2895 ret = translate_error(fs, parent, err);
2896 goto out2;
2897 }
2898
2899 err = ext2fs_link(fs, parent, node_name, child,
2900 filetype);
2901 }
2902 if (err) {
2903 ret = translate_error(fs, parent, err);
2904 goto out2;
2905 }
2906
2907 ret = update_mtime(fs, parent, NULL);
2908 if (ret)
2909 goto out2;
2910
2911 memset(&inode, 0, sizeof(inode));
2912 inode.i_mode = mode;
2913 inode.i_links_count = 1;
2914 inode.i_extra_isize = sizeof(struct ext2_inode_large) -
2915 EXT2_GOOD_OLD_INODE_SIZE;
f150bdec
DW
2916 inode.i_uid = ctxt->uid;
2917 inode.i_gid = ctxt->gid;
7889640d 2918 if (ext2fs_has_feature_extents(fs->super)) {
81cbf1ef
DW
2919 ext2_extent_handle_t handle;
2920
2921 inode.i_flags &= ~EXT4_EXTENTS_FL;
2922 ret = ext2fs_extent_open2(fs, child,
2923 (struct ext2_inode *)&inode, &handle);
2924 if (ret)
2925 return ret;
2926 ext2fs_extent_free(handle);
2927 }
2928
2929 err = ext2fs_write_new_inode(fs, child, (struct ext2_inode *)&inode);
2930 if (err) {
2931 ret = translate_error(fs, child, err);
2932 goto out2;
2933 }
2934
2935 inode.i_generation = ff->next_generation++;
2936 init_times(&inode);
2937 err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode,
2938 sizeof(inode));
2939 if (err) {
2940 ret = translate_error(fs, child, err);
2941 goto out2;
2942 }
2943
2944 ext2fs_inode_alloc_stats2(fs, child, 1, 0);
2945
2946 ret = __op_open(ff, path, fp);
2947 if (ret)
2948 goto out2;
2949out2:
2950 pthread_mutex_unlock(&ff->bfl);
2951out:
2952 free(temp_path);
2953 return ret;
2954}
2955
4e222d9b
TT
2956static int op_ftruncate(const char *path EXT2FS_ATTR((unused)),
2957 off_t len, struct fuse_file_info *fp)
81cbf1ef
DW
2958{
2959 struct fuse_context *ctxt = fuse_get_context();
2960 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
377e3a96
TT
2961 struct fuse2fs_file_handle *fh =
2962 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
81cbf1ef
DW
2963 ext2_filsys fs;
2964 ext2_file_t efp;
2965 errcode_t err;
2966 int ret = 0;
2967
2968 FUSE2FS_CHECK_CONTEXT(ff);
2969 fs = ff->fs;
2970 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2971 dbg_printf("%s: ino=%d len=%jd\n", __func__, fh->ino, len);
2972 pthread_mutex_lock(&ff->bfl);
2973 if (!fs_writeable(fs)) {
2974 ret = -EROFS;
2975 goto out;
2976 }
2977
2978 err = ext2fs_file_open(fs, fh->ino, fh->open_flags, &efp);
2979 if (err) {
2980 ret = translate_error(fs, fh->ino, err);
2981 goto out;
2982 }
2983
2984 err = ext2fs_file_set_size2(efp, len);
2985 if (err) {
2986 ret = translate_error(fs, fh->ino, err);
2987 goto out2;
2988 }
2989
2990out2:
2991 err = ext2fs_file_close(efp);
2992 if (ret)
2993 goto out;
2994 if (err) {
2995 ret = translate_error(fs, fh->ino, err);
2996 goto out;
2997 }
2998
2999 ret = update_mtime(fs, fh->ino, NULL);
3000 if (ret)
3001 goto out;
3002
3003out:
3004 pthread_mutex_unlock(&ff->bfl);
3005 return 0;
3006}
3007
4e222d9b
TT
3008static int op_fgetattr(const char *path EXT2FS_ATTR((unused)),
3009 struct stat *statbuf,
81cbf1ef
DW
3010 struct fuse_file_info *fp)
3011{
3012 struct fuse_context *ctxt = fuse_get_context();
3013 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3014 ext2_filsys fs;
377e3a96
TT
3015 struct fuse2fs_file_handle *fh =
3016 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
81cbf1ef
DW
3017 int ret = 0;
3018
3019 FUSE2FS_CHECK_CONTEXT(ff);
3020 fs = ff->fs;
3021 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3022 dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3023 pthread_mutex_lock(&ff->bfl);
3024 ret = stat_inode(fs, fh->ino, statbuf);
3025 pthread_mutex_unlock(&ff->bfl);
3026
3027 return ret;
3028}
3029
3030static int op_utimens(const char *path, const struct timespec ctv[2])
3031{
3032 struct fuse_context *ctxt = fuse_get_context();
3033 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
4e222d9b 3034 struct timespec tv[2];
81cbf1ef
DW
3035 ext2_filsys fs;
3036 errcode_t err;
3037 ext2_ino_t ino;
3038 struct ext2_inode_large inode;
3039 int ret = 0;
3040
3041 FUSE2FS_CHECK_CONTEXT(ff);
3042 fs = ff->fs;
3043 pthread_mutex_lock(&ff->bfl);
3044 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
3045 if (err) {
3046 ret = translate_error(fs, 0, err);
3047 goto out;
3048 }
3049 dbg_printf("%s: ino=%d\n", __func__, ino);
3050
3051 ret = check_inum_access(fs, ino, W_OK);
3052 if (ret)
3053 goto out;
3054
3055 memset(&inode, 0, sizeof(inode));
3056 err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
3057 sizeof(inode));
3058 if (err) {
3059 ret = translate_error(fs, ino, err);
3060 goto out;
3061 }
3062
4e222d9b
TT
3063 tv[0] = ctv[0];
3064 tv[1] = ctv[1];
81cbf1ef
DW
3065#ifdef UTIME_NOW
3066 if (tv[0].tv_nsec == UTIME_NOW)
3067 get_now(tv);
3068 if (tv[1].tv_nsec == UTIME_NOW)
3069 get_now(tv + 1);
3070#endif /* UTIME_NOW */
3071#ifdef UTIME_OMIT
3072 if (tv[0].tv_nsec != UTIME_OMIT)
3073 EXT4_INODE_SET_XTIME(i_atime, tv, &inode);
3074 if (tv[1].tv_nsec != UTIME_OMIT)
3075 EXT4_INODE_SET_XTIME(i_mtime, tv + 1, &inode);
3076#endif /* UTIME_OMIT */
3077 ret = update_ctime(fs, ino, &inode);
3078 if (ret)
3079 goto out;
3080
3081 err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
3082 sizeof(inode));
3083 if (err) {
3084 ret = translate_error(fs, ino, err);
3085 goto out;
3086 }
3087
3088out:
3089 pthread_mutex_unlock(&ff->bfl);
3090 return ret;
3091}
3092
3093#ifdef SUPPORT_I_FLAGS
3094static int ioctl_getflags(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3095 void *data)
3096{
3097 errcode_t err;
3098 struct ext2_inode_large inode;
3099
3100 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3101 dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3102 memset(&inode, 0, sizeof(inode));
3103 err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3104 sizeof(inode));
3105 if (err)
3106 return translate_error(fs, fh->ino, err);
3107
3108 *(__u32 *)data = inode.i_flags & EXT2_FL_USER_VISIBLE;
3109 return 0;
3110}
3111
3112#define FUSE2FS_MODIFIABLE_IFLAGS \
3113 (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL | EXT2_NODUMP_FL | \
3114 EXT2_NOATIME_FL | EXT3_JOURNAL_DATA_FL | EXT2_DIRSYNC_FL | \
3115 EXT2_TOPDIR_FL)
3116
3117static int ioctl_setflags(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3118 void *data)
3119{
3120 errcode_t err;
3121 struct ext2_inode_large inode;
3122 int ret;
3123 __u32 flags = *(__u32 *)data;
3124 struct fuse_context *ctxt = fuse_get_context();
ea1a3fa2 3125 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
81cbf1ef
DW
3126
3127 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3128 dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3129 memset(&inode, 0, sizeof(inode));
3130 err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3131 sizeof(inode));
3132 if (err)
3133 return translate_error(fs, fh->ino, err);
3134
ea1a3fa2 3135 if (!ff->fakeroot && ctxt->uid != 0 && inode.i_uid != ctxt->uid)
81cbf1ef
DW
3136 return -EPERM;
3137
3138 if ((inode.i_flags ^ flags) & ~FUSE2FS_MODIFIABLE_IFLAGS)
3139 return -EINVAL;
3140
3141 inode.i_flags = (inode.i_flags & ~FUSE2FS_MODIFIABLE_IFLAGS) |
3142 (flags & FUSE2FS_MODIFIABLE_IFLAGS);
3143
3144 ret = update_ctime(fs, fh->ino, &inode);
3145 if (ret)
3146 return ret;
3147
3148 err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3149 sizeof(inode));
3150 if (err)
3151 return translate_error(fs, fh->ino, err);
3152
3153 return 0;
3154}
3155
3156static int ioctl_getversion(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3157 void *data)
3158{
3159 errcode_t err;
3160 struct ext2_inode_large inode;
3161
3162 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3163 dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3164 memset(&inode, 0, sizeof(inode));
3165 err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3166 sizeof(inode));
3167 if (err)
3168 return translate_error(fs, fh->ino, err);
3169
3170 *(__u32 *)data = inode.i_generation;
3171 return 0;
3172}
3173
3174static int ioctl_setversion(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3175 void *data)
3176{
3177 errcode_t err;
3178 struct ext2_inode_large inode;
3179 int ret;
3180 __u32 generation = *(__u32 *)data;
3181 struct fuse_context *ctxt = fuse_get_context();
ea1a3fa2 3182 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
81cbf1ef
DW
3183
3184 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3185 dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3186 memset(&inode, 0, sizeof(inode));
3187 err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3188 sizeof(inode));
3189 if (err)
3190 return translate_error(fs, fh->ino, err);
3191
ea1a3fa2 3192 if (!ff->fakeroot && ctxt->uid != 0 && inode.i_uid != ctxt->uid)
81cbf1ef
DW
3193 return -EPERM;
3194
3195 inode.i_generation = generation;
3196
3197 ret = update_ctime(fs, fh->ino, &inode);
3198 if (ret)
3199 return ret;
3200
3201 err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3202 sizeof(inode));
3203 if (err)
3204 return translate_error(fs, fh->ino, err);
3205
3206 return 0;
3207}
3208#endif /* SUPPORT_I_FLAGS */
3209
3210#ifdef FITRIM
3211static int ioctl_fitrim(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3212 void *data)
3213{
3214 struct fstrim_range *fr = data;
3215 blk64_t start, end, max_blocks, b, cleared;
3216 errcode_t err = 0;
3217
3218 start = fr->start / fs->blocksize;
3219 end = (fr->start + fr->len - 1) / fs->blocksize;
3220 dbg_printf("%s: start=%llu end=%llu\n", __func__, start, end);
3221
3222 if (start < fs->super->s_first_data_block)
3223 start = fs->super->s_first_data_block;
3224 if (start >= ext2fs_blocks_count(fs->super))
3225 start = ext2fs_blocks_count(fs->super) - 1;
3226
3227 if (end < fs->super->s_first_data_block)
3228 end = fs->super->s_first_data_block;
3229 if (end >= ext2fs_blocks_count(fs->super))
3230 end = ext2fs_blocks_count(fs->super) - 1;
3231
3232 cleared = 0;
3233 max_blocks = 2048ULL * 1024 * 1024 / fs->blocksize;
3234
3235 fr->len = 0;
3236 while (start <= end) {
3237 err = ext2fs_find_first_zero_block_bitmap2(fs->block_map,
3238 start, end, &start);
3239 if (err == ENOENT)
3240 return 0;
3241 else if (err)
3242 return translate_error(fs, fh->ino, err);
3243
3244 b = start + max_blocks < end ? start + max_blocks : end;
3245 err = ext2fs_find_first_set_block_bitmap2(fs->block_map,
3246 start, b, &b);
3247 if (err && err != ENOENT)
3248 return translate_error(fs, fh->ino, err);
3249 if (b - start >= fr->minlen) {
3250 err = io_channel_discard(fs->io, start, b - start);
3251 if (err)
3252 return translate_error(fs, fh->ino, err);
3253 cleared += b - start;
3254 fr->len = cleared * fs->blocksize;
3255 }
3256 start = b + 1;
3257 }
3258
3259 return err;
3260}
3261#endif /* FITRIM */
3262
3263#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
4e222d9b
TT
3264static int op_ioctl(const char *path EXT2FS_ATTR((unused)), int cmd,
3265 void *arg EXT2FS_ATTR((unused)),
3266 struct fuse_file_info *fp,
3267 unsigned int flags EXT2FS_ATTR((unused)), void *data)
81cbf1ef
DW
3268{
3269 struct fuse_context *ctxt = fuse_get_context();
3270 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
377e3a96
TT
3271 struct fuse2fs_file_handle *fh =
3272 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
81cbf1ef
DW
3273 ext2_filsys fs;
3274 int ret = 0;
3275
3276 FUSE2FS_CHECK_CONTEXT(ff);
3277 fs = ff->fs;
3278 pthread_mutex_lock(&ff->bfl);
4e222d9b 3279 switch ((unsigned long) cmd) {
81cbf1ef
DW
3280#ifdef SUPPORT_I_FLAGS
3281 case EXT2_IOC_GETFLAGS:
3282 ret = ioctl_getflags(fs, fh, data);
3283 break;
3284 case EXT2_IOC_SETFLAGS:
3285 ret = ioctl_setflags(fs, fh, data);
3286 break;
3287 case EXT2_IOC_GETVERSION:
3288 ret = ioctl_getversion(fs, fh, data);
3289 break;
3290 case EXT2_IOC_SETVERSION:
3291 ret = ioctl_setversion(fs, fh, data);
3292 break;
3293#endif
3294#ifdef FITRIM
3295 case FITRIM:
3296 ret = ioctl_fitrim(fs, fh, data);
3297 break;
3298#endif
3299 default:
3300 dbg_printf("%s: Unknown ioctl %d\n", __func__, cmd);
3301 ret = -ENOTTY;
3302 }
3303 pthread_mutex_unlock(&ff->bfl);
3304
3305 return ret;
3306}
3307#endif /* FUSE 28 */
3308
4e222d9b
TT
3309static int op_bmap(const char *path, size_t blocksize EXT2FS_ATTR((unused)),
3310 uint64_t *idx)
81cbf1ef
DW
3311{
3312 struct fuse_context *ctxt = fuse_get_context();
3313 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3314 ext2_filsys fs;
3315 ext2_ino_t ino;
3316 errcode_t err;
3317 int ret = 0;
3318
3319 FUSE2FS_CHECK_CONTEXT(ff);
3320 fs = ff->fs;
3321 pthread_mutex_lock(&ff->bfl);
3322 err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
3323 if (err) {
3324 ret = translate_error(fs, 0, err);
3325 goto out;
3326 }
3327 dbg_printf("%s: ino=%d blk=%"PRIu64"\n", __func__, ino, *idx);
3328
3329 err = ext2fs_bmap2(fs, ino, NULL, NULL, 0, *idx, 0, (blk64_t *)idx);
3330 if (err) {
3331 ret = translate_error(fs, ino, err);
3332 goto out;
3333 }
3334
3335out:
3336 pthread_mutex_unlock(&ff->bfl);
3337 return ret;
3338}
3339
3340#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
3341# ifdef SUPPORT_FALLOCATE
3342static int fallocate_helper(struct fuse_file_info *fp, int mode, off_t offset,
3343 off_t len)
3344{
3345 struct fuse_context *ctxt = fuse_get_context();
3346 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
377e3a96
TT
3347 struct fuse2fs_file_handle *fh =
3348 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
81cbf1ef
DW
3349 ext2_filsys fs;
3350 struct ext2_inode_large inode;
3351 blk64_t start, end;
3352 __u64 fsize;
3353 errcode_t err;
3354 int flags;
3355
3356 FUSE2FS_CHECK_CONTEXT(ff);
3357 fs = ff->fs;
3358 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3359 start = offset / fs->blocksize;
3360 end = (offset + len - 1) / fs->blocksize;
3361 dbg_printf("%s: ino=%d mode=0x%x start=%jd end=%llu\n", __func__,
3362 fh->ino, mode, offset / fs->blocksize, end);
3363 if (!fs_can_allocate(ff, len / fs->blocksize))
3364 return -ENOSPC;
3365
3366 memset(&inode, 0, sizeof(inode));
3367 err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3368 sizeof(inode));
3369 if (err)
3370 return err;
3371 fsize = EXT2_I_SIZE(&inode);
3372
3373 /* Allocate a bunch of blocks */
3374 flags = (mode & FL_KEEP_SIZE_FLAG ? 0 :
3375 EXT2_FALLOCATE_INIT_BEYOND_EOF);
3376 err = ext2fs_fallocate(fs, flags, fh->ino,
3377 (struct ext2_inode *)&inode,
3378 ~0ULL, start, end - start + 1);
3379 if (err && err != EXT2_ET_BLOCK_ALLOC_FAIL)
3380 return translate_error(fs, fh->ino, err);
3381
3382 /* Update i_size */
3383 if (!(mode & FL_KEEP_SIZE_FLAG)) {
4e222d9b 3384 if ((__u64) offset + len > fsize) {
81cbf1ef
DW
3385 err = ext2fs_inode_size_set(fs,
3386 (struct ext2_inode *)&inode,
3387 offset + len);
3388 if (err)
3389 return translate_error(fs, fh->ino, err);
3390 }
3391 }
3392
3393 err = update_mtime(fs, fh->ino, &inode);
3394 if (err)
3395 return err;
3396
3397 err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3398 sizeof(inode));
3399 if (err)
3400 return translate_error(fs, fh->ino, err);
3401
3402 return err;
3403}
3404
3405static errcode_t clean_block_middle(ext2_filsys fs, ext2_ino_t ino,
3406 struct ext2_inode_large *inode, off_t offset,
3407 off_t len, char **buf)
3408{
3409 blk64_t blk;
3410 off_t residue;
3411 int retflags;
3412 errcode_t err;
3413
3414 residue = offset % fs->blocksize;
3415 if (residue == 0)
3416 return 0;
3417
3418 if (!*buf) {
3419 err = ext2fs_get_mem(fs->blocksize, buf);
3420 if (err)
3421 return err;
3422 }
3423
3424 err = ext2fs_bmap2(fs, ino, (struct ext2_inode *)inode, *buf, 0,
3425 offset / fs->blocksize, &retflags, &blk);
3426 if (err)
3427 return err;
3428 if (!blk || (retflags & BMAP_RET_UNINIT))
3429 return 0;
3430
3431 err = io_channel_read_blk(fs->io, blk, 1, *buf);
3432 if (err)
3433 return err;
3434
3435 memset(*buf + residue, 0, len);
3436
3437 return io_channel_write_blk(fs->io, blk, 1, *buf);
3438}
3439
3440static errcode_t clean_block_edge(ext2_filsys fs, ext2_ino_t ino,
3441 struct ext2_inode_large *inode, off_t offset,
3442 int clean_before, char **buf)
3443{
3444 blk64_t blk;
3445 int retflags;
3446 off_t residue;
3447 errcode_t err;
3448
3449 residue = offset % fs->blocksize;
3450 if (residue == 0)
3451 return 0;
3452
3453 if (!*buf) {
3454 err = ext2fs_get_mem(fs->blocksize, buf);
3455 if (err)
3456 return err;
3457 }
3458
3459 err = ext2fs_bmap2(fs, ino, (struct ext2_inode *)inode, *buf, 0,
3460 offset / fs->blocksize, &retflags, &blk);
3461 if (err)
3462 return err;
3463
3464 err = io_channel_read_blk(fs->io, blk, 1, *buf);
3465 if (err)
3466 return err;
3467 if (!blk || (retflags & BMAP_RET_UNINIT))
3468 return 0;
3469
3470 if (clean_before)
3471 memset(*buf, 0, residue);
3472 else
3473 memset(*buf + residue, 0, fs->blocksize - residue);
3474
3475 return io_channel_write_blk(fs->io, blk, 1, *buf);
3476}
3477
3478static int punch_helper(struct fuse_file_info *fp, int mode, off_t offset,
3479 off_t len)
3480{
3481 struct fuse_context *ctxt = fuse_get_context();
3482 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
377e3a96
TT
3483 struct fuse2fs_file_handle *fh =
3484 (struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
81cbf1ef
DW
3485 ext2_filsys fs;
3486 struct ext2_inode_large inode;
3487 blk64_t start, end;
3488 errcode_t err;
3489 char *buf = NULL;
3490
3491 FUSE2FS_CHECK_CONTEXT(ff);
3492 fs = ff->fs;
3493 FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3494 dbg_printf("%s: offset=%jd len=%jd\n", __func__, offset, len);
3495
3496 /* kernel ext4 punch requires this flag to be set */
3497 if (!(mode & FL_KEEP_SIZE_FLAG))
3498 return -EINVAL;
3499
3500 /* Punch out a bunch of blocks */
3501 start = (offset + fs->blocksize - 1) / fs->blocksize;
3502 end = (offset + len - fs->blocksize) / fs->blocksize;
3503 dbg_printf("%s: ino=%d mode=0x%x start=%llu end=%llu\n", __func__,
3504 fh->ino, mode, start, end);
3505
3506 memset(&inode, 0, sizeof(inode));
3507 err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3508 sizeof(inode));
3509 if (err)
3510 return translate_error(fs, fh->ino, err);
3511
3512 /* Zero everything before the first block and after the last block */
3513 if ((offset / fs->blocksize) == ((offset + len) / fs->blocksize))
3514 err = clean_block_middle(fs, fh->ino, &inode, offset,
3515 len, &buf);
3516 else {
3517 err = clean_block_edge(fs, fh->ino, &inode, offset, 0, &buf);
3518 if (!err)
3519 err = clean_block_edge(fs, fh->ino, &inode,
3520 offset + len, 1, &buf);
3521 }
3522 if (buf)
3523 ext2fs_free_mem(&buf);
3524 if (err)
3525 return translate_error(fs, fh->ino, err);
3526
3527 /* Unmap full blocks in the middle */
3528 if (start <= end) {
3529 err = ext2fs_punch(fs, fh->ino, (struct ext2_inode *)&inode,
3530 NULL, start, end);
3531 if (err)
3532 return translate_error(fs, fh->ino, err);
3533 }
3534
3535 err = update_mtime(fs, fh->ino, &inode);
3536 if (err)
3537 return err;
3538
3539 err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3540 sizeof(inode));
3541 if (err)
3542 return translate_error(fs, fh->ino, err);
3543
3544 return 0;
3545}
3546
4e222d9b
TT
3547static int op_fallocate(const char *path EXT2FS_ATTR((unused)), int mode,
3548 off_t offset, off_t len,
81cbf1ef
DW
3549 struct fuse_file_info *fp)
3550{
3551 struct fuse_context *ctxt = fuse_get_context();
3552 struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3553 ext2_filsys fs = ff->fs;
3554 int ret;
3555
3556 /* Catch unknown flags */
3557 if (mode & ~(FL_PUNCH_HOLE_FLAG | FL_KEEP_SIZE_FLAG))
3558 return -EINVAL;
3559
3560 pthread_mutex_lock(&ff->bfl);
3561 if (!fs_writeable(fs)) {
3562 ret = -EROFS;
3563 goto out;
3564 }
3565 if (mode & FL_PUNCH_HOLE_FLAG)
3566 ret = punch_helper(fp, mode, offset, len);
3567 else
3568 ret = fallocate_helper(fp, mode, offset, len);
3569out:
3570 pthread_mutex_unlock(&ff->bfl);
3571
3572 return ret;
3573}
3574# endif /* SUPPORT_FALLOCATE */
3575#endif /* FUSE 29 */
3576
3577static struct fuse_operations fs_ops = {
3578 .init = op_init,
3579 .destroy = op_destroy,
3580 .getattr = op_getattr,
3581 .readlink = op_readlink,
3582 .mknod = op_mknod,
3583 .mkdir = op_mkdir,
3584 .unlink = op_unlink,
3585 .rmdir = op_rmdir,
3586 .symlink = op_symlink,
3587 .rename = op_rename,
3588 .link = op_link,
3589 .chmod = op_chmod,
3590 .chown = op_chown,
3591 .truncate = op_truncate,
3592 .open = op_open,
3593 .read = op_read,
3594 .write = op_write,
3595 .statfs = op_statfs,
3596 .release = op_release,
3597 .fsync = op_fsync,
3598 .setxattr = op_setxattr,
3599 .getxattr = op_getxattr,
3600 .listxattr = op_listxattr,
3601 .removexattr = op_removexattr,
3602 .opendir = op_open,
3603 .readdir = op_readdir,
3604 .releasedir = op_release,
3605 .fsyncdir = op_fsync,
3606 .access = op_access,
3607 .create = op_create,
3608 .ftruncate = op_ftruncate,
3609 .fgetattr = op_fgetattr,
3610 .utimens = op_utimens,
3611#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
3612# if defined(UTIME_NOW) || defined(UTIME_OMIT)
3613 .flag_utime_omit_ok = 1,
3614# endif
3615#endif
3616 .bmap = op_bmap,
3617#ifdef SUPERFLUOUS
3618 .lock = op_lock,
3619 .poll = op_poll,
3620#endif
3621#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
3622 .ioctl = op_ioctl,
3623 .flag_nullpath_ok = 1,
3624#endif
3625#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
3626 .flag_nopath = 1,
3627# ifdef SUPPORT_FALLOCATE
3628 .fallocate = op_fallocate,
3629# endif
3630#endif
3631};
3632
3633static int get_random_bytes(void *p, size_t sz)
3634{
3635 int fd;
3636 ssize_t r;
3637
4e222d9b 3638 fd = open("/dev/urandom", O_RDONLY);
81cbf1ef 3639 if (fd < 0) {
4e222d9b 3640 perror("/dev/urandom");
81cbf1ef
DW
3641 return 0;
3642 }
3643
3644 r = read(fd, p, sz);
3645
3646 close(fd);
4e222d9b 3647 return (size_t) r == sz;
81cbf1ef
DW
3648}
3649
69df8496
TT
3650enum {
3651 FUSE2FS_VERSION,
3652 FUSE2FS_HELP,
3653 FUSE2FS_HELPFULL,
3654};
3655
3656#define FUSE2FS_OPT(t, p, v) { t, offsetof(struct fuse2fs, p), v }
3657
3658static struct fuse_opt fuse2fs_opts[] = {
3659 FUSE2FS_OPT("ro", ro, 1),
3660 FUSE2FS_OPT("errors=panic", panic_on_error, 1),
3661 FUSE2FS_OPT("minixdf", minixdf, 1),
ea1a3fa2 3662 FUSE2FS_OPT("fakeroot", fakeroot, 1),
69df8496
TT
3663 FUSE2FS_OPT("fuse2fs_debug", debug, 1),
3664 FUSE2FS_OPT("no_default_opts", no_default_opts, 1),
3665
3666 FUSE_OPT_KEY("-V", FUSE2FS_VERSION),
3667 FUSE_OPT_KEY("--version", FUSE2FS_VERSION),
3668 FUSE_OPT_KEY("-h", FUSE2FS_HELP),
3669 FUSE_OPT_KEY("--help", FUSE2FS_HELP),
3670 FUSE_OPT_KEY("--helpfull", FUSE2FS_HELPFULL),
3671 FUSE_OPT_END
3672};
3673
3674
3675static int fuse2fs_opt_proc(void *data, const char *arg,
3676 int key, struct fuse_args *outargs)
81cbf1ef 3677{
69df8496
TT
3678 struct fuse2fs *ff = data;
3679
3680 switch (key) {
3681 case FUSE_OPT_KEY_NONOPT:
3682 if (!ff->device) {
3683 ff->device = strdup(arg);
3684 return 0;
3685 }
3686 return 1;
3687 case FUSE2FS_HELP:
3688 case FUSE2FS_HELPFULL:
3689 fprintf(stderr,
3690 "usage: %s device/image mountpoint [options]\n"
3691 "\n"
3692 "general options:\n"
3693 " -o opt,[opt...] mount options\n"
3694 " -h --help print help\n"
3695 " -V --version print version\n"
3696 "\n"
3697 "fuse2fs options:\n"
3698 " -o ro read-only mount\n"
3699 " -o errors=panic dump core on error\n"
3700 " -o minixdf minix-style df\n"
ea1a3fa2 3701 " -o fakeroot pretend to be root for permission checks\n"
69df8496
TT
3702 " -o no_default_opts do not include default fuse options\n"
3703 " -o fuse2fs_debug enable fuse2fs debugging\n"
3704 "\n",
3705 outargs->argv[0]);
3706 if (key == FUSE2FS_HELPFULL) {
3707 fuse_opt_add_arg(outargs, "-ho");
3708 fuse_main(outargs->argc, outargs->argv, &fs_ops, NULL);
3709 } else {
3710 fprintf(stderr, "Try --helpfull to get a list of "
3711 "all flags, including the FUSE options.\n");
3712 }
3713 exit(1);
3714
3715 case FUSE2FS_VERSION:
3716 fprintf(stderr, "fuse2fs %s (%s)\n", E2FSPROGS_VERSION,
3717 E2FSPROGS_DATE);
3718 fuse_opt_add_arg(outargs, "--version");
3719 fuse_main(outargs->argc, outargs->argv, &fs_ops, NULL);
3720 exit(0);
3721 }
3722 return 1;
81cbf1ef
DW
3723}
3724
3725int main(int argc, char *argv[])
3726{
69df8496
TT
3727 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
3728 struct fuse2fs fctx;
81cbf1ef 3729 errcode_t err;
8feb6f43 3730 char *logfile;
81cbf1ef
DW
3731 char extra_args[BUFSIZ];
3732 int ret = 0, flags = EXT2_FLAG_64BITS | EXT2_FLAG_EXCLUSIVE;
3733
69df8496
TT
3734 memset(&fctx, 0, sizeof(fctx));
3735 fctx.magic = FUSE2FS_MAGIC;
81cbf1ef 3736
69df8496
TT
3737 fuse_opt_parse(&args, &fctx, fuse2fs_opts, fuse2fs_opt_proc);
3738 if (fctx.device == NULL) {
3739 fprintf(stderr, "Missing ext4 device/image\n");
3740 fprintf(stderr, "See '%s -h' for usage\n", argv[0]);
3741 exit(1);
81cbf1ef
DW
3742 }
3743
69df8496 3744 if (fctx.ro)
81cbf1ef
DW
3745 printf("%s", _("Mounting read-only.\n"));
3746
3747#ifdef ENABLE_NLS
3748 setlocale(LC_MESSAGES, "");
3749 setlocale(LC_CTYPE, "");
3750 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
3751 textdomain(NLS_CAT_NAME);
3752 set_com_err_gettext(gettext);
3753#endif
3754 add_error_table(&et_ext2_error_table);
3755
81cbf1ef
DW
3756 /* Set up error logging */
3757 logfile = getenv("FUSE2FS_LOGFILE");
3758 if (logfile) {
69df8496
TT
3759 fctx.err_fp = fopen(logfile, "a");
3760 if (!fctx.err_fp) {
81cbf1ef 3761 perror(logfile);
6ae16a68 3762 goto out;
81cbf1ef
DW
3763 }
3764 } else
69df8496 3765 fctx.err_fp = stderr;
81cbf1ef
DW
3766
3767 /* Will we allow users to allocate every last block? */
3768 if (getenv("FUSE2FS_ALLOC_ALL_BLOCKS")) {
3769 printf(_("%s: Allowing users to allocate all blocks. "
69df8496
TT
3770 "This is dangerous!\n"), fctx.device);
3771 fctx.alloc_all_blocks = 1;
81cbf1ef
DW
3772 }
3773
3774 /* Start up the fs (while we still can use stdout) */
3775 ret = 2;
69df8496 3776 if (!fctx.ro)
81cbf1ef 3777 flags |= EXT2_FLAG_RW;
69df8496 3778 err = ext2fs_open2(fctx.device, NULL, flags, 0, 0, unix_io_manager,
81cbf1ef
DW
3779 &global_fs);
3780 if (err) {
69df8496
TT
3781 printf(_("%s: %s.\n"), fctx.device, error_message(err));
3782 printf(_("Please run e2fsck -fy %s.\n"), fctx.device);
6ae16a68 3783 goto out;
81cbf1ef 3784 }
69df8496
TT
3785 fctx.fs = global_fs;
3786 global_fs->priv_data = &fctx;
81cbf1ef
DW
3787
3788 ret = 3;
aca77cad 3789
7889640d 3790 if (ext2fs_has_feature_journal_needs_recovery(global_fs->super)) {
69df8496
TT
3791 if (!fctx.ro) {
3792 printf(_("%s: recovering journal\n"), fctx.device);
81cbf1ef
DW
3793 err = ext2fs_run_ext3_journal(&global_fs);
3794 if (err) {
69df8496 3795 printf(_("%s: %s.\n"), fctx.device,
81cbf1ef
DW
3796 error_message(err));
3797 printf(_("Please run e2fsck -fy %s.\n"),
69df8496 3798 fctx.device);
81cbf1ef
DW
3799 goto out;
3800 }
7889640d 3801 ext2fs_clear_feature_journal_needs_recovery(global_fs->super);
81cbf1ef
DW
3802 ext2fs_mark_super_dirty(global_fs);
3803 } else {
3804 printf("%s", _("Journal needs recovery; running "
3805 "`e2fsck -E journal_only' is required.\n"));
3806 goto out;
3807 }
3808 }
3809
69df8496 3810 if (!fctx.ro) {
7889640d 3811 if (ext2fs_has_feature_journal(global_fs->super))
81cbf1ef 3812 printf(_("%s: Writing to the journal is not supported.\n"),
69df8496 3813 fctx.device);
81cbf1ef
DW
3814 err = ext2fs_read_inode_bitmap(global_fs);
3815 if (err) {
3816 translate_error(global_fs, 0, err);
3817 goto out;
3818 }
3819 err = ext2fs_read_block_bitmap(global_fs);
3820 if (err) {
3821 translate_error(global_fs, 0, err);
3822 goto out;
3823 }
3824 }
3825
3826 if (!(global_fs->super->s_state & EXT2_VALID_FS))
3827 printf("%s", _("Warning: Mounting unchecked fs, running e2fsck "
3828 "is recommended.\n"));
3829 if (global_fs->super->s_max_mnt_count > 0 &&
3830 global_fs->super->s_mnt_count >= global_fs->super->s_max_mnt_count)
3831 printf("%s", _("Warning: Maximal mount count reached, running "
3832 "e2fsck is recommended.\n"));
3833 if (global_fs->super->s_checkinterval > 0 &&
377e3a96
TT
3834 (time_t) (global_fs->super->s_lastcheck +
3835 global_fs->super->s_checkinterval) <= time(0))
81cbf1ef
DW
3836 printf("%s", _("Warning: Check time reached; running e2fsck "
3837 "is recommended.\n"));
3838 if (global_fs->super->s_last_orphan)
3839 printf("%s",
3840 _("Orphans detected; running e2fsck is recommended.\n"));
3841
3842 if (global_fs->super->s_state & EXT2_ERROR_FS) {
3843 printf("%s",
3844 _("Errors detected; running e2fsck is required.\n"));
3845 goto out;
3846 }
3847
3848 /* Initialize generation counter */
69df8496 3849 get_random_bytes(&fctx.next_generation, sizeof(unsigned int));
81cbf1ef 3850
69df8496 3851 /* Set up default fuse parameters */
81cbf1ef 3852 snprintf(extra_args, BUFSIZ, "-okernel_cache,subtype=ext4,use_ino,"
69df8496 3853 "fsname=%s,attr_timeout=0" FUSE_PLATFORM_OPTS,
4dda2315 3854 fctx.device);
69df8496
TT
3855 if (fctx.no_default_opts == 0)
3856 fuse_opt_add_arg(&args, extra_args);
3857
ea1a3fa2
NC
3858 if (fctx.fakeroot) {
3859#ifdef HAVE_MOUNT_NODEV
3860 fuse_opt_add_arg(&args,"-onodev");
3861#endif
3862#ifdef HAVE_MOUNT_NOSUID
3863 fuse_opt_add_arg(&args,"-onosuid");
3864#endif
3865 }
3866
69df8496
TT
3867 if (fctx.debug) {
3868 int i;
3869
3870 printf("fuse arguments:");
3871 for (i = 0; i < args.argc; i++)
3872 printf(" '%s'", args.argv[i]);
3873 printf("\n");
3874 }
81cbf1ef 3875
69df8496
TT
3876 pthread_mutex_init(&fctx.bfl, NULL);
3877 fuse_main(args.argc, args.argv, &fs_ops, &fctx);
3878 pthread_mutex_destroy(&fctx.bfl);
81cbf1ef
DW
3879
3880 ret = 0;
3881out:
6ae16a68
TT
3882 if (global_fs) {
3883 err = ext2fs_close(global_fs);
3884 if (err)
3885 com_err(argv[0], err, "while closing fs");
3886 global_fs = NULL;
3887 }
81cbf1ef
DW
3888 return ret;
3889}
3890
3891static int __translate_error(ext2_filsys fs, errcode_t err, ext2_ino_t ino,
3892 const char *file, int line)
3893{
3894 struct timespec now;
3895 int ret = err;
3896 struct fuse2fs *ff = fs->priv_data;
3897 int is_err = 0;
3898
3899 /* Translate ext2 error to unix error code */
3900 if (err < EXT2_ET_BASE)
3901 goto no_translation;
3902 switch (err) {
3903 case EXT2_ET_NO_MEMORY:
3904 case EXT2_ET_TDB_ERR_OOM:
3905 ret = -ENOMEM;
3906 break;
3907 case EXT2_ET_INVALID_ARGUMENT:
3908 case EXT2_ET_LLSEEK_FAILED:
3909 ret = -EINVAL;
3910 break;
3911 case EXT2_ET_NO_DIRECTORY:
3912 ret = -ENOTDIR;
3913 break;
3914 case EXT2_ET_FILE_NOT_FOUND:
3915 ret = -ENOENT;
3916 break;
3917 case EXT2_ET_DIR_NO_SPACE:
3918 is_err = 1;
da9d5b80 3919 /* fallthrough */
81cbf1ef
DW
3920 case EXT2_ET_TOOSMALL:
3921 case EXT2_ET_BLOCK_ALLOC_FAIL:
3922 case EXT2_ET_INODE_ALLOC_FAIL:
3923 case EXT2_ET_EA_NO_SPACE:
3924 ret = -ENOSPC;
3925 break;
3926 case EXT2_ET_SYMLINK_LOOP:
3927 ret = -EMLINK;
3928 break;
3929 case EXT2_ET_FILE_TOO_BIG:
3930 ret = -EFBIG;
3931 break;
3932 case EXT2_ET_TDB_ERR_EXISTS:
3933 case EXT2_ET_FILE_EXISTS:
3934 ret = -EEXIST;
3935 break;
3936 case EXT2_ET_MMP_FAILED:
3937 case EXT2_ET_MMP_FSCK_ON:
3938 ret = -EBUSY;
3939 break;
3940 case EXT2_ET_EA_KEY_NOT_FOUND:
3941#ifdef ENODATA
3942 ret = -ENODATA;
3943#else
3944 ret = -ENOENT;
3945#endif
3946 break;
3947 /* Sometimes fuse returns a garbage file handle pointer to us... */
3948 case EXT2_ET_MAGIC_EXT2_FILE:
3949 ret = -EFAULT;
3950 break;
3951 case EXT2_ET_UNIMPLEMENTED:
3952 ret = -EOPNOTSUPP;
3953 break;
3954 default:
3955 is_err = 1;
3956 ret = -EIO;
3957 break;
3958 }
3959
3960no_translation:
3961 if (!is_err)
3962 return ret;
3963
3964 if (ino)
3965 fprintf(ff->err_fp, "FUSE2FS (%s): %s (inode #%d) at %s:%d.\n",
da9d5b80 3966 fs->device_name ? fs->device_name : "???",
81cbf1ef
DW
3967 error_message(err), ino, file, line);
3968 else
3969 fprintf(ff->err_fp, "FUSE2FS (%s): %s at %s:%d.\n",
da9d5b80 3970 fs->device_name ? fs->device_name : "???",
81cbf1ef
DW
3971 error_message(err), file, line);
3972 fflush(ff->err_fp);
3973
3974 /* Make a note in the error log */
3975 get_now(&now);
3976 fs->super->s_last_error_time = now.tv_sec;
3977 fs->super->s_last_error_ino = ino;
3978 fs->super->s_last_error_line = line;
3979 fs->super->s_last_error_block = err; /* Yeah... */
3980 strncpy((char *)fs->super->s_last_error_func, file,
3981 sizeof(fs->super->s_last_error_func));
3982 if (fs->super->s_first_error_time == 0) {
3983 fs->super->s_first_error_time = now.tv_sec;
3984 fs->super->s_first_error_ino = ino;
3985 fs->super->s_first_error_line = line;
3986 fs->super->s_first_error_block = err;
3987 strncpy((char *)fs->super->s_first_error_func, file,
3988 sizeof(fs->super->s_first_error_func));
3989 }
3990
3991 fs->super->s_error_count++;
3992 ext2fs_mark_super_dirty(fs);
3993 ext2fs_flush(fs);
3994 if (ff->panic_on_error)
3995 abort();
3996
3997 return ret;
3998}