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