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