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