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