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