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