Compare commits

...
280 Commits
Author SHA1 Message Date
trapexitandGitHub 0b0f0a1b9e Merge pull request #663 from trapexit/random
only return 1 branch for rand/eprand policies
2019-09-07 17:27:56 -04:00
Antonio SJ Musumeci 0fffabfbe3 only return 1 branch for rand/eprand policies 2019-09-07 17:25:06 -04:00
trapexitandGitHub 6b3f703ba9 Merge pull request #662 from trapexit/unlink
initialize mutex to fix lockup
2019-09-07 15:14:10 -04:00
Antonio SJ Musumeci 50ad648ce4 initialize mutex to fix lockup 2019-09-07 14:10:36 -04:00
trapexitandGitHub 2dbcd2b07a Merge pull request #660 from trapexit/docs
add UPGRADE section
2019-09-03 21:43:47 -04:00
Antonio SJ Musumeci 752a15953a add UPGRADE section 2019-09-03 21:43:18 -04:00
trapexitandGitHub 23d365f67b Merge pull request #659 from zofrex/relink-mount-mergerfs
Force symlink creation (don't error if it already exists)
2019-08-31 13:46:13 -04:00
James Sanderson f77d1d9929 Force symlink creation (don't error if it already exists) 2019-08-31 18:41:54 +01:00
trapexitandGitHub 4204c807bc Merge pull request #657 from trapexit/docs
update how it works
2019-08-20 20:16:03 -04:00
Antonio SJ Musumeci e6a6ab967b update how it works 2019-08-20 20:13:25 -04:00
trapexitandGitHub 52e4d60e7c Merge pull request #655 from tnilanon/master
Update README.md
2019-08-15 06:22:39 -04:00
Tanachat NilanonandGitHub 38919add61 Update README.md
Fixed typo: changed ' to `
2019-08-14 23:57:56 -07:00
trapexitandGitHub a7244184bd Merge pull request #653 from xlotlu/patch-1
fix some grammar and typos
2019-08-01 08:06:52 -04:00
Ionuț CiocîrlanandGitHub 86bda61aa7 fix some grammar and typos 2019-08-01 14:35:00 +03:00
trapexitandGitHub 10e5829b8e Merge pull request #643 from trapexit/ioctl_setuid
set uid & gid when calling ioctl
2019-06-17 17:09:16 -04:00
Antonio SJ Musumeci 4c4c27a93e set uid & gid when calling ioctl
Turns out certain ioctl calls check the effective user id (FS_IOC_SETFLAGS).
2019-06-17 13:37:15 -04:00
trapexitandGitHub 72ac1fc0d1 Merge pull request #639 from trapexit/args
accept old arguments for backwards compatibility
2019-06-10 20:24:36 -04:00
Antonio SJ Musumeci 5ca928e436 accept old arguments for backwards compatibility 2019-06-10 20:20:41 -04:00
trapexitandGitHub 5d013f4a18 Merge pull request #636 from trapexit/max_pages
allow setting of 'max_pages' (via 'fuse_msg_size')
2019-06-03 21:16:53 -04:00
Antonio SJ Musumeci 7cbd88ac81 allow setting of 'max_pages' (via 'fuse_msg_size')
Linux 4.20 and above allow setting the number of pages per FUSE message
upto 256 (4K * 256 = 1MiB). This can greatly increase read and write
speeds depending on the workload.
2019-06-03 21:01:19 -04:00
trapexitandGitHub 24af276542 Merge pull request #635 from trapexit/copy_file_range
add copy_file_range support
2019-06-03 08:31:22 -04:00
Antonio SJ Musumeci 8cb7195c3e add copy_file_range support 2019-06-03 07:12:05 -04:00
trapexitandGitHub c8e178bf71 Merge pull request #633 from trapexit/cache.files
add file caching across opens and runtime control
2019-05-30 00:28:28 -04:00
Antonio SJ Musumeci 529a953e30 add file caching across opens and runtime control 2019-05-30 00:10:08 -04:00
trapexitandGitHub 02b657edff Merge pull request #632 from trapexit/async-read
jmake async_read optional again
2019-05-28 17:10:17 -04:00
Antonio SJ Musumeci ddf6a2f105 make async_read optional again 2019-05-28 15:57:50 -04:00
trapexitandGitHub 40a4762cac Merge pull request #630 from trapexit/cache-dir
add readdir caching
2019-05-23 22:26:19 -04:00
Antonio SJ Musumeci 2323c16316 add readdir caching 2019-05-23 22:11:33 -04:00
trapexitandGitHub bac4b33ef8 Merge pull request #629 from trapexit/cache-symlink
add symlink caching
2019-05-22 19:50:49 -04:00
Antonio SJ Musumeci 1baa706d37 add symlink caching 2019-05-22 19:25:38 -04:00
trapexitandGitHub 9e3331dab4 Merge pull request #628 from trapexit/hide-cleanup
fix for unlink race condition
2019-05-21 23:09:13 -04:00
Antonio SJ Musumeci 61cded5b34 fix for unlink race condition 2019-05-21 22:57:02 -04:00
trapexitandGitHub 060cae6270 Merge pull request #627 from trapexit/symlink
fix mount.mergerfs generation
2019-05-20 08:18:21 -04:00
Antonio SJ Musumeci 229d8517c0 fix mount.mergerfs generation 2019-05-20 08:17:06 -04:00
trapexitandGitHub cc9381f578 Merge pull request #624 from trapexit/parallel_dirops
ensure parallel dirops is enabled if capable
2019-05-20 00:37:56 -04:00
Antonio SJ Musumeci 5f2221155c ensure parallel dirops is enabled if capable 2019-05-20 00:36:42 -04:00
trapexitandGitHub 7da8dd6b7a Merge pull request #623 from trapexit/async_dio
ensure async_aio is enabled if capable
2019-05-20 00:22:06 -04:00
Antonio SJ Musumeci 2b019b84b0 ensure async_aio is enabled if capable 2019-05-20 00:18:56 -04:00
trapexitandGitHub 741c559df1 Merge pull request #622 from trapexit/rename
ensure marking open files renamed over as hidden
2019-05-19 23:43:24 -04:00
Antonio SJ Musumeci 3a66a68edb ensure marking open files renamed over as hidden 2019-05-19 23:25:46 -04:00
trapexitandGitHub af1c0d78e8 Merge pull request #621 from trapexit/posix-acl
add support for POSIX ACLs
2019-05-19 18:26:49 -04:00
Antonio SJ Musumeci 80d56ac94e add support for POSIX ACLs 2019-05-19 18:17:55 -04:00
trapexitandGitHub 41881f9d05 Merge pull request #620 from trapexit/flock
remove 'remote' flock support
2019-05-19 17:40:03 -04:00
Antonio SJ Musumeci 1ca70521a4 remove 'remote' flock support 2019-05-19 17:34:56 -04:00
trapexitandGitHub ee0d87d712 Merge pull request #619 from trapexit/hiddenfiles
fix renaming over open unlinked file
2019-05-16 14:49:38 -04:00
Antonio SJ Musumeci c21aa34221 fix renaming over open unlinked file 2019-05-16 14:40:30 -04:00
trapexitandGitHub 1ad79067e4 Merge pull request #617 from trapexit/docs
update support section of README
2019-05-12 23:58:28 -04:00
Antonio SJ Musumeci 810871d2df update support section of README 2019-05-12 23:57:15 -04:00
trapexitandGitHub 6404939156 Merge pull request #615 from trapexit/fsname
fix setting of fsname
2019-05-12 14:30:37 -04:00
Antonio SJ Musumeci e052446713 fix setting of fsname 2019-05-12 14:07:21 -04:00
trapexitandGitHub 5e16851c79 Merge pull request #611 from trapexit/man
tweak docs
2019-05-10 12:03:22 -04:00
Antonio SJ Musumeci 5883020784 tweak docs 2019-05-10 11:54:41 -04:00
trapexitandGitHub 726c1c850c Merge pull request #610 from trapexit/tests
create integration tests
2019-05-05 17:50:08 -04:00
Antonio SJ Musumeci 374580a85d create integration tests 2019-05-04 17:16:52 -04:00
trapexitandGitHub 4293cb7253 Merge pull request #609 from trapexit/make
cleanup and rework build system
2019-05-03 18:49:45 -04:00
Antonio SJ Musumeci 825fcf7f35 cleanup and rework build system 2019-05-03 09:42:15 -04:00
trapexitandGitHub 85e2a3e71b Merge pull request #605 from trapexit/man
add reference to 32bit mmap kernel bug
2019-04-23 20:02:01 -04:00
Antonio SJ Musumeci 3288d834a9 add reference to 32bit mmap kernel bug 2019-04-23 20:01:36 -04:00
trapexitandGitHub 209dc2252a Merge pull request #603 from trapexit/backcompat
fix outarg size to accomidate newer fuse_kernel.h on older platforms
2019-04-16 22:23:03 -04:00
Antonio SJ Musumeci df0d0552b2 fix outarg size calculation to accomidate newer fuse_kernel.h on older platforms 2019-04-16 22:13:32 -04:00
trapexitandGitHub 05f33c84e4 Merge pull request #601 from trapexit/hidden
remove .fuse_hidden file creation
2019-04-14 19:52:19 -04:00
Antonio SJ Musumeci 6ecc618d83 remove .fuse_hidden file creation
addresses #521

mergerfs is written using libfuse's high level API. The HLAPI forces a certain
behavior with regard to unlinking or rename overwriting of open files. It
renames the file to .fuse_hiddenXXXXXX and when incoming requests refer
to the unlinked file it will use path based calls and use that path.

This behavior leads to rmdirs failing or some software noticing
the .fuse_hidden files.

This patch changes the HLAPI and removes entirely the .fuse_hidden behavior.

See the README for more.
2019-04-13 21:41:51 -04:00
trapexitandGitHub 46be946672 Merge pull request #599 from trapexit/clonefile
fall back to other file copy methods in clonefile
2019-04-13 15:15:37 -04:00
Antonio SJ Musumeci 2a075ead92 fall back to other file copy methods in clonefile 2019-04-13 15:08:13 -04:00
trapexitandGitHub 8bd09628ef Merge pull request #593 from trapexit/outbuf
ioctl: don't set outbufsz when not needed
2019-03-20 10:30:56 -04:00
Antonio SJ Musumeci b69819e4b2 ioctl: don't set outbufsz when not needed 2019-03-20 10:18:55 -04:00
trapexitandGitHub 2ca0cb0fbf Merge pull request #592 from trapexit/tarball
makefile: remove superclean dependency from tarball
2019-03-12 23:24:41 -04:00
Antonio SJ Musumeci 61d764d0fd makefile: remove superclean dependency from tarball 2019-03-12 23:24:17 -04:00
trapexitandGitHub 8b007ada61 Merge pull request #591 from trapexit/parallel-deb
parallel deb building
2019-03-12 23:14:06 -04:00
Antonio SJ Musumeci b0b265b8e5 parallel deb building 2019-03-12 23:11:27 -04:00
trapexitandGitHub cab7033d5b Merge pull request #589 from trapexit/make
rework makefiles for better manage parallel builds
2019-03-10 19:39:08 -04:00
Antonio SJ Musumeci 1be9900733 rework makefiles for better manage parallel builds 2019-03-10 19:29:35 -04:00
trapexitandGitHub 3c2a9cd4f8 Merge pull request #586 from trapexit/man
replace {attr,entry,negative}_timeout references
2019-02-23 01:40:08 -05:00
Antonio SJ Musumeci 38037feab7 replace {attr,entry,negative}_timeout references 2019-02-23 01:39:28 -05:00
trapexitandGitHub 99d44cfc5d Merge pull request #585 from trapexit/debfix
fix building of deb pkg
2019-02-23 01:35:59 -05:00
Antonio SJ Musumeci 2af0dcd273 fix building of deb pkg 2019-02-23 01:35:22 -05:00
trapexitandGitHub d9f430fda8 Merge pull request #584 from trapexit/timeouts
make attr, entry, negative_entry cache timeouts runtime configurable
2019-02-23 01:24:45 -05:00
Antonio SJ Musumeci 0918dfd117 make attr, entry, negative_entry cache timeouts runtime configurable 2019-02-23 01:03:20 -05:00
trapexitandGitHub a64c7c97ad Merge pull request #583 from trapexit/libfuse
replace libfuse's autoconf with makefile and ecfd
2019-02-18 21:46:10 -05:00
Antonio SJ Musumeci 95c0cc741d replace libfuse's autoconf with makefile 2019-02-18 21:36:32 -05:00
trapexitandGitHub 8b0342067c Merge pull request #582 from trapexit/discord
add discord server to docs
2019-02-17 14:55:56 -05:00
Antonio SJ Musumeci 1d48dba0b7 add discord server to docs 2019-02-17 14:46:50 -05:00
trapexitandGitHub e8622fdd64 Merge pull request #581 from trapexit/ioctl
fix FS_IOC_{GET,SET}{FLAGS,VERSION} ioctl calls
2019-02-17 13:11:57 -05:00
Antonio SJ Musumeci 7bf607bb6b fix FS_IOC_{GET,SET}{FLAGS,VERSION} ioctl calls 2019-02-17 11:48:19 -05:00
trapexitandGitHub a80f9a0b29 Merge pull request #580 from trapexit/freebsd
misc fixes for FreeBSD
2019-02-06 23:43:16 -05:00
Antonio SJ Musumeci 940c323251 misc fixes for FreeBSD 2019-02-06 23:20:28 -05:00
trapexitandGitHub babe8bcf47 Merge pull request #579 from trapexit/freebsd
remove O_LARGEFILE
2019-02-06 21:14:50 -05:00
Antonio SJ Musumeci 5ab7d2dd72 remove O_LARGEFILE 2019-02-06 21:06:11 -05:00
trapexitandGitHub 401502579b Merge pull request #577 from trapexit/modules
remove libfuse modules
2019-02-03 19:56:45 -05:00
Antonio SJ Musumeci 65d3bfe84d remove libfuse modules 2019-02-03 19:49:11 -05:00
trapexitandGitHub cfd5d31338 Merge pull request #575 from trapexit/cleanup
general code cleanup
2019-01-31 23:50:40 -05:00
Antonio SJ Musumeci 9d9ee7b71d general code cleanup 2019-01-31 22:47:09 -05:00
trapexitandGitHub 5a1a60742e Merge pull request #574 from trapexit/opts
remove `defaults`, hard code atomic_o_trunc, big_writes, and default_…
2019-01-30 22:53:35 -05:00
Antonio SJ Musumeci c5b2415daf remove defaults, hard code atomic_o_trunc, big_writes, and default_permissions
`defaults` is a value used by all filesystems and isn't passed through to
mergerfs when mounting via the fstab or the mount command. This led
to inconsistent application of options. atomic_o_trunc, big_writes, and
default_permissions should be enabled all the time anyway and splice_*
can lead to issues so they are not always enabled.
2019-01-30 22:46:21 -05:00
trapexitandGitHub a0bb2f8480 Merge pull request #568 from trapexit/docs
fix <> escaping in argument list
2019-01-24 11:16:55 -05:00
Antonio SJ Musumeci f4a06cae18 fix <> escaping in argument list 2019-01-24 11:15:55 -05:00
trapexitandGitHub 21d690a210 Merge pull request #567 from trapexit/statfs_cache
add statfs cache
2019-01-23 23:11:17 -05:00
Antonio SJ Musumeci 5be7e007ce add statfs cache 2019-01-23 23:06:07 -05:00
trapexitandGitHub f42bd8666e Merge pull request #565 from trapexit/open_cache
add policy cache for 'open'
2019-01-22 22:50:25 -05:00
Antonio SJ Musumeci 7a057daa0c add policy cache for 'open'
A fusepath -> basepath cache for `open` to limit the overhead of FUSE in 'open, read/write, close' patterns (such as Transmission).
2019-01-22 09:21:15 -05:00
trapexitandGitHub 8e0aa1d9a6 Merge pull request #564 from trapexit/nfs
add mention of noforget argument for NFS exports
2019-01-21 18:42:19 -05:00
Antonio SJ Musumeci a13b822543 add mention of noforget argument for NFS exports 2019-01-21 18:41:19 -05:00
trapexitandGitHub 40319081e0 Merge pull request #563 from trapexit/ioctl
make ioctl on directories use open policy
2019-01-18 22:58:13 -05:00
Antonio SJ Musumeci 9fd3b968fc make ioctl on directories use open policy 2019-01-18 22:41:52 -05:00
trapexitandGitHub 24a7973955 Merge pull request #559 from trapexit/docs
clarify descriptions regarding funcitons and those without policies
2019-01-15 10:26:46 -05:00
Antonio SJ Musumeci a57c680cc8 clarify descriptions regarding funcitons and those without policies 2019-01-15 10:18:57 -05:00
trapexitandGitHub 11be067895 Merge pull request #558 from trapexit/docs
add more info on different caching techniques
2019-01-15 09:51:09 -05:00
Antonio SJ Musumeci 3a1213435f add more info on different caching techniques 2019-01-15 09:39:39 -05:00
trapexitandGitHub 56f7df028b Merge pull request #556 from trapexit/direct
set direct_io per open/create, now runtime configurable
2019-01-11 15:36:39 -05:00
Antonio SJ Musumeci 87b2795f2b set direct_io per open/create, now runtime configurable 2019-01-11 15:23:14 -05:00
trapexitandGitHub c36bc5320d Merge pull request #555 from trapexit/docs
misc doc updates
2019-01-09 11:31:40 -05:00
Antonio SJ Musumeci 7eefb58ff7 misc doc updates 2019-01-09 11:25:06 -05:00
trapexitandGitHub 6a247501e1 Merge pull request #552 from trapexit/enospc
update README regarding valid ENOSPC errors
2019-01-07 09:26:35 -05:00
Antonio SJ Musumeci 0b5a0d1228 update README regarding valid ENOSPC errors 2019-01-07 09:20:34 -05:00
trapexitandGitHub 8686eadcf4 Merge pull request #550 from trapexit/mv_warning
mention mv quirk in known issues
2019-01-06 13:24:51 -05:00
Antonio SJ Musumeci aa56e12040 mention mv quirk in known issues 2019-01-06 13:24:12 -05:00
trapexitandGitHub adcbf0eef0 Merge pull request #549 from trapexit/cow
optimize link_cow eligibility check
2019-01-04 10:53:19 -05:00
Antonio SJ Musumeci 10f7f8bdea optimize link_cow eligibility check 2019-01-04 10:21:28 -05:00
trapexitandGitHub 90e422c113 Merge pull request #544 from trapexit/newest
check minfreespace on newest policy create
2018-12-12 15:56:58 -05:00
Antonio SJ Musumeci dfa1c1ad6f check minfreespace on newest policy create 2018-12-12 15:53:53 -05:00
trapexitandGitHub bd792757e0 Merge pull request #543 from trapexit/docs
misc README updates
2018-12-12 15:52:18 -05:00
Antonio SJ Musumeci 40969402e8 misc README updates 2018-12-12 15:48:53 -05:00
trapexitandGitHub fee9a449ba Merge pull request #539 from trapexit/makefile_cleanup
general cleanup of makefile, add static & lto building
2018-12-02 15:34:14 -05:00
Antonio SJ Musumeci 6de8e4471c general cleanup of makefile, add static & lto building 2018-12-02 15:30:15 -05:00
trapexitandGitHub f0f64f8ed1 Merge pull request #537 from trapexit/alpine
fix building on alpine w/ musl
2018-11-28 19:40:53 -05:00
Antonio SJ Musumeci 6ae68465cf fix building on alpine w/ musl 2018-11-28 17:08:40 -05:00
trapexitandGitHub 3c1f19e85a Merge pull request #534 from trapexit/xattr
change xattr setting notsup to nosys
2018-11-19 23:32:07 -05:00
trapexitandGitHub 2a8a6b8fe0 Merge pull request #533 from trapexit/truncate
fix indexing of truncate targets
2018-11-19 23:31:12 -05:00
Antonio SJ Musumeci 7d9458fdd1 change xattr setting notsup to nosys 2018-11-19 23:30:39 -05:00
Antonio SJ Musumeci 43b676a6e2 fix indexing of truncate targets 2018-11-19 23:25:16 -05:00
trapexitandGitHub 606d9c4d3f Merge pull request #531 from trapexit/o_path
fix building on platforms without O_PATH
2018-11-06 08:15:02 -05:00
Antonio SJ Musumeci c46134c03a fix building on platforms without O_PATH 2018-11-06 07:59:28 -05:00
trapexitandGitHub 0abb2a960c Merge pull request #530 from trapexit/dedup
optimize readdir file dedup
2018-11-06 00:12:49 -05:00
Antonio SJ Musumeci 3631ab7df2 optimize readdir file dedup
Use fasthash64 to hash filenames to uint64_t and store in khash
set. Significantly reduces malloc/free'ing and memory usage.
2018-11-06 00:05:30 -05:00
trapexitandGitHub b8b3ab06a7 Merge pull request #529 from trapexit/statvfs
add ability to change statfs behavior
2018-11-05 21:38:41 -05:00
Antonio SJ Musumeci 680f8194f9 add ability to change statfs behavior 2018-11-05 21:33:27 -05:00
trapexitandGitHub 3d33428a4e Merge pull request #528 from trapexit/nc
rename NW (no write) to NC (no create)
2018-11-01 23:38:14 -04:00
Antonio SJ Musumeci 7524e57262 rename NW (no write) to NC (no create) 2018-11-01 23:37:45 -04:00
trapexitandGitHub 1195e66a8a Merge pull request #527 from trapexit/branch_tagging
add tagging branches RW/RO/NW
2018-11-01 23:22:59 -04:00
Antonio SJ Musumeci b55ebba4ed add tagging branches RW/RO/NW
This allows users to tag a branch as readonly or not for writing regardless
of how the filesystem is mounted. Should simplify deployments and offer
more flexibility.
2018-11-01 23:13:49 -04:00
trapexitandGitHub 8dd0dc11ee Merge pull request #525 from trapexit/docs
misc updates to docs
2018-10-31 10:28:01 -04:00
Antonio SJ Musumeci 8eacb008b3 misc updates to docs 2018-10-31 10:22:40 -04:00
trapexitandGitHub 9c16ab6999 Merge pull request #520 from trapexit/cleanups
misc cleanups
2018-10-24 22:47:28 -04:00
Antonio SJ Musumeci 9e0ab1f518 misc cleanups 2018-10-24 22:38:36 -04:00
trapexitandGitHub 47bf58eae9 Merge pull request #517 from trapexit/cleanup
policy return cleanup
2018-10-15 19:19:37 -04:00
Antonio SJ Musumeci 8a48b74cb4 policy return cleanup 2018-10-15 19:03:02 -04:00
trapexitandGitHub 570c93ec2c Merge pull request #516 from trapexit/clone
add FICLONE and copy_file_range to clonefile
2018-10-12 10:42:26 -04:00
Antonio SJ Musumeci 85026d5780 add FICLONE and copy_file_range to clonefile
If available FICLONE and copy_file_range will be tried in addition to sendfile
when copying data between two files. The fallback is a tradition read/write
loop. On systems that support these it should improve performance.
2018-10-12 10:18:49 -04:00
trapexitandGitHub bb2e6eb605 Merge pull request #515 from trapexit/xattr.h
remove libattr dependency
2018-10-09 14:00:50 -04:00
Antonio SJ Musumeci 1885a82cce remove libattr dependency 2018-10-09 13:50:45 -04:00
trapexitandGitHub 602a37b231 Merge pull request #514 from trapexit/runtime_xattr
add ability to turn on/off xattr support at runtime
2018-10-09 08:52:55 -04:00
Antonio SJ Musumeci 65f482e483 add ability to turn on/off xattr support at runtime 2018-10-09 08:41:31 -04:00
trapexitandGitHub 6ee44e451c Merge pull request #513 from trapexit/errno
fix building on certain platforms
2018-10-09 08:25:05 -04:00
Antonio SJ Musumeci 8d1a1564bf fix building on certain platforms 2018-10-09 08:23:37 -04:00
trapexitandGitHub 4af9248eba Merge pull request #509 from trapexit/cow
add link_cow feature
2018-10-06 22:48:01 -04:00
Antonio SJ Musumeci 93f7d7d927 add link_cow feature
When enabled if a regular file is opened which has a link count > 1 it will
copy the file to a temporary file and rename over the original. Effectively
breaking the link. This behavior is similar to cow-shell and other LD_PRELOAD
based "CoW" solutions.
2018-10-06 22:05:05 -04:00
trapexitandGitHub 19a7d43b31 Merge pull request #506 from trapexit/literal_glob
keep literal when glob fails
2018-10-01 17:12:40 -04:00
Antonio SJ Musumeci 9afefef032 keep literal when glob fails 2018-10-01 16:56:40 -04:00
trapexitandGitHub 8c3462caf2 Merge pull request #505 from trapexit/depends
add fuse to debian pkg dependency
2018-09-30 23:46:18 -04:00
Antonio SJ Musumeci 340f3c85c9 add fuse to debian pkg dependency 2018-09-30 23:45:46 -04:00
trapexitandGitHub ff04098319 Merge pull request #504 from trapexit/disable_security.capabilities
add security_capability option
2018-09-30 23:34:07 -04:00
Antonio SJ Musumeci f8563369bc add security_capability option 2018-09-30 23:30:53 -04:00
trapexitandGitHub 4152769182 Merge pull request #499 from trapexit/docs
add comment regarding tar error
2018-09-06 08:28:40 -04:00
Antonio SJ Musumeci 057eafef7f add comment regarding tar error 2018-09-06 08:28:21 -04:00
trapexitandGitHub c7e93720ff Merge pull request #496 from trapexit/doc-updates
tweak docs, add FAQ regarding vendoring of libfuse
2018-08-20 13:40:41 -04:00
Antonio SJ Musumeci 587ab62583 tweak docs, add FAQ regarding vendoring of libfuse 2018-08-20 13:40:01 -04:00
trapexitandGitHub a894360402 Merge pull request #495 from ahippo/external-fuse
Option for building with system libfuse
2018-08-20 12:05:37 -04:00
Andrey Mazo 756d4ff0ff Makefile: option for building with system libfuse
Add INTERNAL_FUSE variable to control linking against
bundled libfuse vs external/system libfuse.
If external libfuse is requested,
`pkg-config` is used to obtain CFLAGS/LIBS/LDFLAGS and
to check that the provided external libfuse is >= 2.9.7.

This might hopefully get mergerfs closer to inclusion into distros.

Link: https://github.com/trapexit/mergerfs/issues/431
Link: https://bugs.gentoo.org/587956#c6
2018-08-20 00:05:58 +03:00
Andrey Mazo ec6adaa376 options: move "-o threads=" help text to libfuse/
Parsing of and acting upon "-o threads" option is done in the bundled `libfuse/`,
so move the corresponding help text there too.
This make help text consistent with behavior
when building against system libfuse,
which doesn't support this option.
2018-08-19 21:04:35 +03:00
trapexitandGitHub dee2c3e23b Merge pull request #494 from trapexit/hardlinks
add FAQ entry on hard links
2018-08-18 22:10:54 -04:00
Antonio SJ Musumeci fc52f89ddc add FAQ entry on hard links 2018-08-18 22:10:23 -04:00
trapexitandGitHub fdbafa63ba Merge pull request #493 from ahippo/ldflags
Makefile: don't touch LDFLAGS
2018-08-13 07:18:58 -04:00
Andrey Mazo e987ff46c2 Makefile: don't touch LDFLAGS
These are more like LIBS rather than LDFLAGS.
They are used just in one place,
so simply put them inline.

Also, use LDFLAGS provided by the user during actual link.

This helps users pass their own LDFLAGS.
For example, this is important on Gentoo,
where LDFLAGS='-Wl,-O1 -Wl,--as-needed' is passed by default.
2018-08-13 06:02:29 +03:00
trapexitandGitHub b1ecc58114 Merge pull request #491 from trapexit/inode_docs
add details regarding use_ino
2018-07-25 17:29:06 -04:00
Antonio SJ Musumeci 39d5ab8e83 add details regarding use_ino 2018-07-25 17:28:36 -04:00
trapexitandGitHub 4b1f9afe1e Merge pull request #482 from trapexit/docs
change examples to use /mnt rather than /tmp
2018-05-04 08:59:27 -04:00
Antonio SJ Musumeci c005463111 change examples to use /mnt rather than /tmp 2018-05-04 09:00:27 -04:00
trapexitandGitHub 50384f4e86 Merge pull request #475 from trapexit/version
fix version.hpp creation, again
2018-03-24 06:53:35 -07:00
Antonio SJ Musumeci 73e8867400 fix version.hpp creation, again 2018-03-24 09:51:25 -04:00
trapexitandGitHub 0545da67ff Merge pull request #474 from trapexit/version
fix versioning with tarball building
2018-03-16 23:27:04 -04:00
Antonio SJ Musumeci 24e690b995 fix versioning with tarball building 2018-03-16 23:26:29 -04:00
trapexitandGitHub 89200a0ab8 Merge pull request #473 from trapexit/version
version bumps and calculation fixes
2018-03-09 21:14:44 -05:00
Antonio SJ Musumeci e521833cec bump change date on readme and rebuild man 2018-03-09 21:12:52 -05:00
Antonio SJ Musumeci 737d941941 bump builtin libfuse version 2018-03-09 21:10:09 -05:00
Antonio SJ Musumeci 9830e29945 fix version generation 2018-03-09 21:06:00 -05:00
trapexitandGitHub 6418b00ac3 Merge pull request #472 from trapexit/clonepathperms
ignore clonepath metadata errors. fixes #470
2018-03-08 16:56:33 -05:00
Antonio SJ Musumeci cfe9c28a10 ignore clonepath metadata errors. fixes #470 2018-03-08 16:55:35 -05:00
trapexitandGitHub aa6e4c1865 Merge pull request #471 from trapexit/clonepath
stop clonepath at base directory. fixes #467
2018-03-08 16:48:53 -05:00
Antonio SJ Musumeci f48c16d162 stop clonepath at base directory. fixes #467 2018-03-07 18:46:32 -05:00
trapexitandGitHub 62ae871d51 Merge pull request #469 from trapexit/hard_remove
add hard_remove details and comment on unionfs
2018-03-03 13:25:15 -05:00
trapexitandGitHub 906702de77 add hard_remove details and comment on unionfs 2018-03-03 13:24:49 -05:00
trapexitandGitHub db27a91a58 Merge pull request #461 from agsimmons/master
Remove duplicate word in README
2018-01-18 15:41:57 -05:00
Andrew SimmonsandGitHub b4a003c5a8 Remove duplicate word in README 2018-01-18 15:38:16 -05:00
trapexitandGitHub b48054fa2c add XRP to support list 2017-12-21 09:47:53 -05:00
trapexitandGitHub d8f05ac8ae add BCH, ETH, & LTC donation addresses 2017-12-20 22:11:26 -05:00
trapexitandGitHub 8843ace757 Merge pull request #454 from trapexit/faq
add explination in FAQ about what mergerfs is / is not
2017-11-15 16:40:24 -05:00
Antonio SJ Musumeci 7d93d5917e add explination in FAQ about what mergerfs is / is not 2017-11-15 16:39:25 -05:00
trapexitandGitHub 8846a135bc Merge pull request #452 from trapexit/faq
faq answer on epmfs
2017-11-07 14:49:38 -05:00
Antonio SJ Musumeci 7207e7fdd6 faq answer on epmfs 2017-11-07 14:48:38 -05:00
trapexitandGitHub a8e6128034 Merge pull request #451 from trapexit/faq
update FAQ and misc tweaks
2017-11-07 09:00:29 -05:00
Antonio SJ Musumeci f72bb1e1ed update FAQ and misc tweaks 2017-11-07 08:59:49 -05:00
trapexitandGitHub cf5d28ea4a Merge pull request #450 from trapexit/support
add support info and how mergerfs works section
2017-11-05 13:44:40 -05:00
Antonio SJ Musumeci bd14f33c31 add support info and how mergerfs works section 2017-11-05 13:43:33 -05:00
trapexitandGitHub 73561c1861 Merge pull request #449 from trapexit/issue-template
Create issue_template.md
2017-11-05 12:10:15 -05:00
trapexitandGitHub 43d50ca471 Create issue_template.md 2017-11-05 12:09:53 -05:00
trapexitandGitHub 8ea0b395b2 Merge pull request #445 from trapexit/setreuid
call 32bit versions of set/geteuid on 32bit platforms
2017-10-17 22:23:27 -04:00
Antonio SJ Musumeci 1d6d22727c call 32bit versions of set/geteuid on 32bit platforms 2017-10-17 22:21:29 -04:00
Antonio SJ MusumeciandGitHub b3c10f5bdf Merge pull request #435 from trapexit/man
rebuild manpage
2017-08-06 14:43:03 -04:00
Antonio SJ Musumeci 821d1b6964 rebuild manpage 2017-08-06 14:42:35 -04:00
Antonio SJ MusumeciandGitHub 6067478e00 Merge pull request #434 from trapexit/makefile
fixup makefile
2017-08-06 14:41:11 -04:00
Antonio SJ Musumeci ebe737e995 fixup makefile 2017-08-06 14:39:56 -04:00
Antonio SJ MusumeciandGitHub e2a9509896 Merge pull request #433 from trapexit/doc-update
misc updates to docs
2017-08-06 14:34:14 -04:00
Antonio SJ MusumeciandGitHub 9104f25c09 misc updates to docs 2017-08-06 14:33:59 -04:00
Antonio SJ MusumeciandGitHub 713c911264 Merge pull request #429 from trapexit/support
expand support section of readme
2017-07-30 16:53:26 -04:00
Antonio SJ MusumeciandGitHub c1d85ef825 expand support section of readme 2017-07-30 16:52:29 -04:00
Antonio SJ MusumeciandGitHub 43eaf29df5 Merge pull request #428 from trapexit/cacheinfo
add info on creating a caching behavior
2017-07-23 19:59:26 -04:00
Antonio SJ MusumeciandGitHub cc1f07ef39 add info on creating a caching behavior 2017-07-23 19:59:11 -04:00
Antonio SJ MusumeciandGitHub c35a4dadee Merge pull request #424 from trapexit/threading
Threading
2017-07-03 00:02:35 -04:00
Antonio SJ Musumeci 75ed37a11a add setting of thread pool size 2017-07-02 23:50:39 -04:00
Antonio SJ Musumeci 8043829815 fixed threads 2017-07-01 23:29:47 -04:00
Antonio SJ MusumeciandGitHub deb70c7a4f Merge pull request #423 from trapexit/khash
improve khash performance
2017-07-01 11:54:39 -04:00
Antonio SJ Musumeci 0708110ec1 improve khash performance 2017-07-01 11:53:35 -04:00
Antonio SJ MusumeciandGitHub dae637925b Merge pull request #422 from trapexit/pragma
use pragma once in headers
2017-06-30 11:53:31 -04:00
Antonio SJ Musumeci a7b126cb48 use pragma once in headers 2017-06-30 11:38:34 -04:00
Antonio SJ MusumeciandGitHub d66774d3f3 Merge pull request #421 from trapexit/ignorepponrename
add 'ignore path preserving on rename' feature
2017-06-30 00:02:08 -04:00
Antonio SJ Musumeci a2bddec8c7 add 'ignore path preserving on rename' feature 2017-06-30 00:01:00 -04:00
Antonio SJ MusumeciandGitHub b95fbd76ec Merge pull request #420 from trapexit/mkstemp-movefile
use temp files (then rename) when moving files for moveonenospc
2017-06-28 21:18:59 -04:00
Antonio SJ Musumeci aea2b40dda use temp files (then rename) when moving files for moveonenospc 2017-06-28 21:17:47 -04:00
Antonio SJ MusumeciandGitHub fa3ff40218 Merge pull request #418 from trapexit/fix
use fusepath from fileinfo. closes #417
2017-06-24 17:04:37 -04:00
Antonio SJ Musumeci bfd410def2 use fusepath from fileinfo. closes #417 2017-06-24 17:03:41 -04:00
Antonio SJ MusumeciandGitHub 721bd4d337 Merge pull request #416 from trapexit/time
add time.h to fix compiling on some platforms
2017-06-15 19:36:31 -04:00
Antonio SJ Musumeci 7296d3d90d add time.h to fix compiling on some platforms 2017-06-15 19:35:28 -04:00
Antonio SJ MusumeciandGitHub a7cddefcc9 Merge pull request #415 from trapexit/static
add libfuse 2.9.7 to repo and build against libfuse.a
2017-06-02 16:14:54 -04:00
Antonio SJ Musumeci de0985c135 add libfuse 2.9.7 to repo and build against libfuse.a 2017-06-02 11:25:25 -04:00
Antonio SJ MusumeciandGitHub 986f230ba7 Merge pull request #412 from trapexit/benchmark
add nullrw feature to facilitate benchmarking
2017-05-26 19:51:28 -04:00
Antonio SJ Musumeci 87c2f2f9dc add nullrw feature to facilitate benchmarking 2017-05-26 18:11:18 -04:00
Antonio SJ MusumeciandGitHub 63f84b255f Merge pull request #409 from trapexit/ro-symlinks
symlinkify: file -> symlink-to-original-file after timeout
2017-05-05 00:47:24 -04:00
Antonio SJ Musumeci 6a7675f2bf symlinkify: file -> symlink-to-original-file after timeout 2017-05-05 00:14:04 -04:00
Antonio SJ MusumeciandGitHub 25ce9938c6 Merge pull request #405 from trapexit/runtime-drop
make dropcacheonclose runtime configurable
2017-04-21 17:00:12 -04:00
Antonio SJ Musumeci 8ba3a08f40 make dropcacheonclose runtime configurable 2017-04-21 16:58:39 -04:00
Antonio SJ MusumeciandGitHub 23dbe48324 Merge pull request #403 from trapexit/copyfile
better handle incomplete reads/writes in copying files
2017-04-13 13:21:34 -04:00
Antonio SJ Musumeci ccaa458739 better handle incomplete reads/writes in copying files 2017-04-13 12:55:34 -04:00
Antonio SJ MusumeciandGitHub f95b07f83b Merge pull request #402 from trapexit/nopath
enable nopath and nullpath_ok
2017-04-12 14:39:44 -04:00
Antonio SJ Musumeci 162b99e6b8 enable nopath and nullpath_ok 2017-04-12 13:52:06 -04:00
Antonio SJ MusumeciandGitHub 3c8afc1bb0 Merge pull request #400 from trapexit/movefile-tweak
tweak movefile behavior
2017-04-11 15:25:07 -04:00
Antonio SJ Musumeci f15437c713 tweak movefile behavior 2017-04-11 15:24:09 -04:00
Antonio SJ MusumeciandGitHub d9be1c4841 Merge pull request #399 from trapexit/travis
add more travis build targets
2017-04-11 10:07:35 -04:00
Antonio SJ Musumeci 5f3aa6eee5 add more travis build targets 2017-04-11 10:00:37 -04:00
Antonio SJ MusumeciandGitHub 1089af9077 Merge pull request #398 from trapexit/fadvise
hide fs::fadvise as it's not used directly
2017-04-11 09:59:00 -04:00
Antonio SJ Musumeci 2fbeb67dd9 hide fs::fadvise as it's not used directly 2017-04-11 09:42:33 -04:00
Antonio SJ MusumeciandGitHub c4ad239171 Merge pull request #397 from trapexit/fadvise
support older libfuse without utime_omit_ok flag
2017-04-11 09:32:36 -04:00
Antonio SJ Musumeci 8b976ab3c1 support older libfuse without utime_omit_ok flag 2017-04-11 09:23:40 -04:00
Antonio SJ MusumeciandGitHub 1499ccf3fb Merge pull request #396 from trapexit/fadvise
fadvise cleanup
2017-04-11 09:03:12 -04:00
Antonio SJ Musumeci 1a1fa06aa3 fadvise cleanup 2017-04-11 09:02:05 -04:00
Antonio SJ MusumeciandGitHub e3e764ecae Merge pull request #395 from trapexit/utime-omit
enable utime_omit_ok flag
2017-04-10 21:38:54 -04:00
Antonio SJ Musumeci 617195d71e enable utime_omit_ok flag 2017-04-10 21:36:56 -04:00
Antonio SJ MusumeciandGitHub 8cfb1cbee4 Merge pull request #394 from trapexit/getgrouplist
work around getgrouplist signature difference on osx
2017-04-08 10:24:26 -04:00
Antonio SJ Musumeci be3eb7e3ed work around getgrouplist signature difference on osx 2017-04-07 16:23:18 -04:00
Antonio SJ MusumeciandGitHub 1c3b72de09 Merge pull request #393 from trapexit/inode
handle 32bit and 64bit inode recalculation
2017-04-07 10:47:49 -04:00
Antonio SJ Musumeci 0600734942 handle 32bit and 64bit inode recalculation 2017-04-07 09:47:19 -04:00
Antonio SJ MusumeciandGitHub e6dc8c2cb3 Merge pull request #392 from trapexit/fadvise
restructure fadvise
2017-04-07 00:22:12 -04:00
Antonio SJ Musumeci 9d0798dbfb restructure fadvise 2017-04-07 00:12:57 -04:00
Antonio SJ MusumeciandGitHub 581356a0c3 Merge pull request #391 from trapexit/fallocate
restructure fallocate abstraction
2017-04-06 23:40:41 -04:00
Antonio SJ Musumeci e2acffe55b restructure fallocate abstraction 2017-04-06 23:35:31 -04:00
Antonio SJ MusumeciandGitHub 998966e6e6 Merge pull request #390 from trapexit/futimesat
abstract futimesat
2017-04-06 23:21:41 -04:00
Antonio SJ Musumeci 42d454ac27 abstract futimesat 2017-04-06 23:13:02 -04:00
Antonio SJ MusumeciandGitHub ad6062b9a8 Merge pull request #389 from trapexit/stattime
abstract access to highres atime/mtime
2017-04-06 22:22:48 -04:00
Antonio SJ Musumeci 0b2bf17cd7 abstract access to highres atime/mtime 2017-04-06 22:16:17 -04:00
Antonio SJ MusumeciandGitHub 292b850e07 Merge pull request #388 from trapexit/types
use correct integer types
2017-04-06 21:35:52 -04:00
Antonio SJ Musumeci e20d566f96 use correct integer types 2017-04-06 21:29:39 -04:00
Antonio SJ MusumeciandGitHub 776ff3e3f1 Merge pull request #387 from trapexit/cppfind
use compiler's preprocessor rather than cpp explicitly
2017-04-06 21:15:02 -04:00
Antonio SJ Musumeci 1539aca3d8 use compiler's preprocessor rather than cpp explicitly 2017-04-06 21:08:55 -04:00
Antonio SJ MusumeciandGitHub 3244314310 Merge pull request #386 from trapexit/travis-ci
setup travis-ci
2017-04-04 08:41:32 -04:00
Antonio SJ Musumeci 9d799ffc9f setup travis-ci 2017-04-04 08:32:36 -04:00
Antonio SJ MusumeciandGitHub 9486bc9b21 Merge pull request #385 from trapexit/clone-errors
make fs::attr return ENOTSUP on EINVAL #381
2017-04-04 06:57:42 -04:00
Antonio SJ Musumeci c043ef95a3 make fs::attr return ENOTSUP on EINVAL #381 2017-04-03 21:11:20 -04:00
Antonio SJ MusumeciandGitHub 3728e39655 Merge pull request #383 from trapexit/docs
explicitly define path preservation, better explain move issues
2017-04-03 14:36:07 -04:00
Antonio SJ Musumeci 215f129a2a explicitly define path preservation, better explain move issues 2017-04-03 14:35:08 -04:00
Antonio SJ MusumeciandGitHub af9a71f84c Merge pull request #382 from trapexit/docs
fix incorrect section header syntax
2017-04-03 12:06:26 -04:00
Antonio SJ Musumeci bb4ec913c6 fix incorrect section header syntax 2017-04-03 12:05:51 -04:00
368 changed files with 39813 additions and 8731 deletions
+34
View File
@@ -0,0 +1,34 @@
General description
===================
Expected behavior
=================
Actual behavior
===============
**Precise** steps to reproduce the behavior
===========================================
> Explicitly list **all** steps to reproduce. Preferably create a minimal example of the problem using standard command line tools. The more variables (apps, settings, etc.) that are involved the more difficult it is to debug. Also, **please** be sure to have read all of the README. It contains a lot of information regarding known system and user issues.
System information
==================
Please provide as much of the following information as possible:
* [ ] mergerfs version: `mergerfs -V`
* [ ] mergerfs settings: `cat /etc/fstab` or the command line arguments
* [ ] Linux version: `uname -a`
* [ ] Versions of any additional software being used
* [ ] List of drives, filesystems, & sizes: `df -h`
* [ ] strace of application having problem: `strace -f -o /tmp/app.strace.txt <cmd>` or `strace -f -p <appPID> -o /tmp/app.strace.txt`
* [ ] strace of mergerfs while app tried to do it's thing: `strace -f -p <mergerfsPID> -o /tmp/mergerfs.strace.txt`
+34
View File
@@ -0,0 +1,34 @@
language: cpp
matrix:
include:
- os: linux
dist: precise
compiler: gcc
sudo: required
- os: linux
dist: precise
compiler: clang
sudo: required
- os: linux
dist: trusty
compiler: gcc
sudo: required
- os: linux
dist: trusty
compiler: clang
sudo: required
- os: linux
dist: xenial
compiler: gcc
sudo: required
- os: linux
dist: xenial
compiler: clang
sudo: required
script:
- sudo -E apt-get install fakeroot
- sudo -E make install-build-pkgs
- make
- make deb
+124 -105
View File
@@ -12,74 +12,74 @@
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
GIT = git
TAR = tar
MKDIR = mkdir
TOUCH = touch
CP = cp
RM = rm
LN = ln
FIND = find
INSTALL = install
MKTEMP = mktemp
STRIP = strip
PANDOC = pandoc
SED = sed
RPMBUILD = rpmbuild
GIT2DEBCL = ./tools/git2debcl
PKGCONFIG = pkg-config
PKGCONFIG = $(shell which pkg-config)
GIT = $(shell which git)
TAR = $(shell which tar)
MKDIR = $(shell which mkdir)
TOUCH = $(shell which touch)
CP = $(shell which cp)
RM = $(shell which rm)
LN = $(shell which ln)
FIND = $(shell which find)
INSTALL = $(shell which install)
MKTEMP = $(shell which mktemp)
STRIP = $(shell which strip)
PANDOC = $(shell which pandoc)
SED = $(shell which sed)
GZIP = $(shell which gzip)
RPMBUILD = $(shell which rpmbuild)
GIT2DEBCL = ./tools/git2debcl
CPPFIND = ./tools/cppfind
ifeq ($(PKGCONFIG),"")
$(error "pkg-config not installed")
GIT_REPO = 0
ifneq ($(shell $(GIT) --version 2> /dev/null),)
ifeq ($(shell test -e .git; echo $$?),0)
GIT_REPO = 1
endif
endif
ifeq ($(PANDOC),"")
$(warning "pandoc does not appear available: manpage won't be buildable")
USE_XATTR = 1
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -Ilibfuse/include
ifeq ($(DEBUG),1)
DEBUG_FLAGS := -g
else
DEBUG_FLAGS :=
endif
XATTR_AVAILABLE = $(shell test ! -e /usr/include/attr/xattr.h; echo $$?)
FUSE_AVAILABLE = $(shell ! pkg-config --exists fuse; echo $$?)
ifeq ($(FUSE_AVAILABLE),0)
FUSE_AVAILABLE = $(shell test ! -e /usr/include/fuse.h; echo $$?)
ifeq ($(STATIC),1)
STATIC_FLAGS := -static
else
STATIC_FLAGS :=
endif
ifeq ($(FUSE_AVAILABLE),0)
$(error "FUSE development package doesn't appear available")
ifeq ($(LTO),1)
LTO_FLAGS := -flto
else
LTO_FLAGS :=
endif
FLAG_NOPATH = $(shell $(CPPFIND) "flag_nopath")
FALLOCATE = $(shell $(CPPFIND) "fuse_fs_fallocate")
FLOCK = $(shell $(CPPFIND) "fuse_fs_flock")
READ_BUF = $(shell $(CPPFIND) "fuse_fs_read_buf")
WRITE_BUF = $(shell $(CPPFIND) "fuse_fs_write_buf")
UGID_USE_RWLOCK = 0
OPTS = -O2
SRC = $(wildcard src/*.cpp)
OBJ = $(SRC:src/%.cpp=obj/%.o)
DEPS = $(OBJ:obj/%.o=obj/%.d)
TARGET = mergerfs
MANPAGE = $(TARGET).1
FUSE_CFLAGS = $(shell $(PKGCONFIG) --cflags fuse)
CFLAGS = -g -Wall \
OBJS = $(SRC:src/%.cpp=build/%.o)
DEPS = $(SRC:src/%.cpp=build/%.d)
MANPAGE = mergerfs.1
CXXFLAGS += \
$(OPTS) \
$(DEBUG_FLAGS) \
$(STATIC_FLAGS) \
$(LTO_FLAGS) \
-Wall \
-Wno-unused-result \
$(FUSE_CFLAGS) \
-DFUSE_USE_VERSION=29 \
-MMD \
-DFLAG_NOPATH=$(FLAG_NOPATH) \
-DFALLOCATE=$(FALLOCATE) \
-DFLOCK=$(FLOCK) \
-DREAD_BUF=$(READ_BUF) \
-DWRITE_BUF=$(WRITE_BUF) \
-DUSE_XATTR=$(USE_XATTR) \
-DUGID_USE_RWLOCK=$(UGID_USE_RWLOCK)
LDFLAGS = $(shell $(PKGCONFIG) fuse --libs)
LDFLAGS += \
-pthread \
-lrt
PREFIX = /usr/local
EXEC_PREFIX = $(PREFIX)
@@ -94,77 +94,76 @@ INSTALLBINDIR = $(DESTDIR)$(BINDIR)
INSTALLSBINDIR = $(DESTDIR)$(SBINDIR)
INSTALLMAN1DIR = $(DESTDIR)$(MAN1DIR)
ifeq ($(XATTR_AVAILABLE),0)
$(warning "xattr not available: disabling")
CFLAGS += -DWITHOUT_XATTR
endif
all: $(TARGET)
.PHONY: all
all: mergerfs
.PHONY: help
help:
@echo "usage: make"
@echo "make XATTR_AVAILABLE=0 - to build program without xattrs functionality (auto discovered otherwise)"
@echo "usage: make\n"
@echo "make USE_XATTR=0 - build program without xattrs functionality"
@echo "make STATIC=1 - build static binary"
@echo "make LTO=1 - build with link time optimization"
$(TARGET): src/version.hpp obj/obj-stamp $(OBJ)
$(CXX) $(CFLAGS) $(OBJ) -o $@ $(LDFLAGS)
objects: version build/stamp
$(MAKE) $(OBJS)
mount.mergerfs: $(TARGET)
$(LN) -fs "$<" "$@"
build/mergerfs: libfuse objects
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OBJS) -o $@ libfuse/build/libfuse.a $(LDFLAGS)
mergerfs: build/mergerfs
changelog:
$(GIT2DEBCL) --name $(TARGET) > ChangeLog
ifeq ($(GIT_REPO),1)
$(GIT2DEBCL) --name mergerfs > ChangeLog
else
@echo "WARNING: need git repo to generate ChangeLog"
endif
authors:
$(GIT) log --format='%aN <%aE>' | sort -f | uniq > AUTHORS
.PHONY: version
version:
tools/update-version
src/version.hpp:
$(eval VERSION := $(shell $(GIT) describe --always --tags --dirty))
@echo "#ifndef _VERSION_HPP" > src/version.hpp
@echo "#define _VERSION_HPP" >> src/version.hpp
@echo "static const char MERGERFS_VERSION[] = \"$(VERSION)\";" >> src/version.hpp
@echo "#endif" >> src/version.hpp
obj/obj-stamp:
$(MKDIR) -p obj
build/stamp:
$(MKDIR) -p build
$(TOUCH) $@
obj/%.o: src/%.cpp
$(CXX) $(CFLAGS) -c $< -o $@
build/%.o: src/%.cpp
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< -o $@
.PHONY: clean
clean: rpm-clean
ifneq ($(GIT),)
ifeq ($(shell test -e .git; echo $$?),0)
$(RM) -f src/version.hpp
endif
endif
$(RM) -rf obj
$(RM) -f "$(TARGET)" mount.mergerfs
$(RM) -rf build
$(FIND) . -name "*~" -delete
$(MAKE) -C libfuse clean
distclean: clean
$(GIT) clean -fd
ifeq ($(GIT_REPO),1)
$(GIT) clean -xfd
endif
.PHONY: install
install: install-base install-mount.mergerfs install-man
install-base: $(TARGET)
install-base: build/mergerfs
$(MKDIR) -p "$(INSTALLBINDIR)"
$(INSTALL) -v -m 0755 "$(TARGET)" "$(INSTALLBINDIR)/$(TARGET)"
$(INSTALL) -v -m 0755 build/mergerfs "$(INSTALLBINDIR)/mergerfs"
install-mount.mergerfs: mount.mergerfs
install-mount.mergerfs: install-base
$(MKDIR) -p "$(INSTALLBINDIR)"
$(CP) -a "$<" "$(INSTALLBINDIR)/$<"
$(LN) -fs "mergerfs" "$(INSTALLBINDIR)/mount.mergerfs"
install-man: $(MANPAGE)
$(MKDIR) -p "$(INSTALLMAN1DIR)"
$(INSTALL) -v -m 0644 "man/$(MANPAGE)" "$(INSTALLMAN1DIR)/$(MANPAGE)"
install-strip: install-base
$(STRIP) "$(INSTALLBINDIR)/$(TARGET)"
$(STRIP) "$(INSTALLBINDIR)/mergerfs"
.PHONY: uninstall
uninstall: uninstall-base uninstall-mount.mergerfs uninstall-man
uninstall-base:
$(RM) -f "$(INSTALLBINDIR)/$(TARGET)"
$(RM) -f "$(INSTALLBINDIR)/mergerfs"
uninstall-mount.mergerfs:
$(RM) -f "$(INSTALLBINDIR)/mount.mergerfs"
@@ -173,16 +172,19 @@ uninstall-man:
$(RM) -f "$(INSTALLMAN1DIR)/$(MANPAGE)"
$(MANPAGE): README.md
ifneq (,$(PANDOC))
ifneq ($(shell $(PANDOC) --version 2> /dev/null),)
$(PANDOC) -s -t man -o "man/$(MANPAGE)" README.md
else
$(warning "pandoc does not appear available: unable to build manpage")
endif
man: $(MANPAGE)
tarball: clean man changelog authors src/version.hpp
$(eval VERSION := $(shell $(GIT) describe --always --tags --dirty))
.PHONY: tarball
tarball: man changelog version
$(eval VERSION := $(shell cat VERSION))
$(eval VERSION := $(subst -,_,$(VERSION)))
$(eval FILENAME := $(TARGET)-$(VERSION))
$(eval FILENAME := mergerfs-$(VERSION))
$(eval TMPDIR := $(shell $(MKTEMP) --tmpdir -d .$(FILENAME).XXXXXXXX))
$(MKDIR) $(TMPDIR)/$(FILENAME)
$(CP) -ar . $(TMPDIR)/$(FILENAME)
@@ -190,27 +192,44 @@ tarball: clean man changelog authors src/version.hpp
$(RM) -rf $(TMPDIR)
debian-changelog:
$(GIT2DEBCL) --name $(TARGET) > debian/changelog
ifeq ($(GIT_REPO),1)
$(GIT2DEBCL) --name mergerfs > debian/changelog
else
cp ChangeLog debian/changelog
endif
signed-deb: debian-changelog
dpkg-buildpackage
signed-deb:
$(MAKE) distclean
$(MAKE) debian-changelog
dpkg-source -b .
dpkg-buildpackage -nc
deb: debian-changelog
dpkg-buildpackage -uc -us
deb:
$(MAKE) distclean
$(MAKE) debian-changelog
dpkg-source -b .
dpkg-buildpackage -nc -uc -us
.PHONY: rpm-clean
rpm-clean:
$(RM) -rf rpmbuild
rpm: tarball
$(eval VERSION := $(shell $(GIT) describe --always --tags --dirty))
$(eval VERSION := $(shell cat VERSION))
$(eval VERSION := $(subst -,_,$(VERSION)))
$(MKDIR) -p rpmbuild/BUILD rpmbuild/RPMS rpmbuild/SOURCES
$(SED) 's/__VERSION__/$(VERSION)/g' $(TARGET).spec > \
rpmbuild/SOURCES/$(TARGET).spec
cp -ar $(TARGET)-$(VERSION).tar.gz rpmbuild/SOURCES
$(RPMBUILD) -ba rpmbuild/SOURCES/$(TARGET).spec \
$(SED) 's/__VERSION__/$(VERSION)/g' mergerfs.spec > \
rpmbuild/SOURCES/mergerfs.spec
cp -ar mergerfs-$(VERSION).tar.gz rpmbuild/SOURCES
$(RPMBUILD) -ba rpmbuild/SOURCES/mergerfs.spec \
--define "_topdir $(CURDIR)/rpmbuild"
.PHONY: all clean install help
.PHONY: install-build-pkgs
install-build-pkgs:
tools/install-build-pkgs
include $(wildcard obj/*.d)
.PHONY: libfuse
libfuse:
$(MAKE) -C libfuse
-include $(DEPS)
+725 -143
View File
File diff suppressed because it is too large Load Diff
+5 -8
View File
@@ -2,10 +2,7 @@ Source: mergerfs
Section: utils
Priority: optional
Maintainer: Antonio SJ Musumeci <trapexit@spawn.link>
Build-Depends: debhelper (>= 8.0.0),
libfuse-dev,
libattr1-dev,
pkg-config
Build-Depends: debhelper (>= 8.0.0)
Standards-Version: 3.9.4
Homepage: http://github.com/trapexit/mergerfs
@@ -13,8 +10,8 @@ Package: mergerfs
Architecture: any
Depends: ${shlibs:Depends},
${misc:Depends},
libfuse2
fuse [linux-any] | fuse4bsd [kfreebsd-any]
Description: another FUSE union filesystem
mergerfs is similar to mhddfs, unionfs, and aufs. Like mhddfs in that it too
uses FUSE. Like aufs in that it provides multiple policies for how to handle
behavior.
mergerfs is a union filesystem geared towards simplifying storage and
management of files across numerous commodity storage devices. It is
similar to mhddfs, unionfs, and aufs.
+1 -1
View File
@@ -5,7 +5,7 @@
#export DH_VERBOSE=1
%:
dh $@
dh $@ --parallel
override_dh_auto_install:
$(MAKE) DESTDIR=$(CURDIR)/debian/mergerfs PREFIX=/usr install
+59
View File
@@ -0,0 +1,59 @@
Current Maintainer
------------------
Nikolaus Rath <Nikolaus@rath.org>
Past Maintainers
----------------
Miklos Szeredi <miklos@szeredi.hu> (until 12/2015)
Contributors
------------
CUSE has been written by Tejun Heo <teheo@suse.de>. Furthermore, the
following people have contributed patches (autogenerated list):
Anatol Pomozov <anatol.pomozov@gmail.com>
Antonio SJ Musumeci <trapexit@spawn.link>
Christopher Harrison <ch12@sanger.ac.uk>
Csaba Henk <csaba.henk@creo.hu>
cvs2git <>
Dalvik Khertel <khertel@outlook.com>
Daniel Thau <danthau@bedrocklinux.org>
David McNab <david@rebirthing.co.nz>
David Sheets <sheets@alum.mit.edu>
Emmanuel Dreyfus <manu@netbsd.org>
Enke Chen <enkechen@yahoo.com>
Eric Engestrom <eric@engestrom.ch>
Eric Wong <normalperson@yhbt.net>
Fabrice Bauzac <fbauzac@amadeus.com>
Feng Shuo <steve.shuo.feng@gmail.com>
Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Ikey Doherty <michael.i.doherty@intel.com>
Jan Blumschein <jan@jan-blumschein.de>
Joachim Schiele <joachim.schiele@daimler.com>
Joachim Schiele <js@lastlog.de>
John Muir <john@jmuir.com>
Laszlo Papp <ext-laszlo.papp@nokia.com>
Madan Valluri <mvalluri@cumulus-systems.com>
Mark Glines <mark@glines.org>
Max Krasnyansky <maxk@kernel.org>
Michael Grigoriev <mag@luminal.org>
Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredi <mszeredi@suse.cz>
mkmm@gmx-topmail.de <mkmm@gmx-topmail.de>
Natanael Copa <ncopa@alpinelinux.org>
Nikolaus Rath <Nikolaus@rath.org>
Olivier Blin <olivier.blin@softathome.com>
Ratna_Bolla@dell.com <Ratna_Bolla@dell.com>
Reuben Hawkins <reubenhwk@gmail.com>
Richard W.M. Jones <rjones@redhat.com>
Riku Voipio <riku.voipio@linaro.org>
Roland Bauerschmidt <rb@debian.org>
Sam Stuewe <halosghost@archlinux.info>
Sebastian Pipping <sebastian@pipping.org>
therealneworld@gmail.com <therealneworld@gmail.com>
Winfried Koehler <w_scan@gmx-topmail.de>
+339
View File
@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
+502
View File
@@ -0,0 +1,502 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
+3547
View File
File diff suppressed because it is too large Load Diff
+84
View File
@@ -0,0 +1,84 @@
VERSION = "2.9.7-mergerfs_2.28.0"
OPTS = -O2
ifeq ($(DEBUG),1)
DEBUG_FLAGS := -g
else
DEBUG_FLAGS :=
endif
DESTDIR = "/"
BINDIR = "/bin"
SBINDIR = "/sbin"
SRC = \
lib/buffer.c \
lib/cuse_lowlevel.c \
lib/fuse.c \
lib/fuse_kern_chan.c \
lib/fuse_loop.c \
lib/fuse_loop_mt.c \
lib/fuse_lowlevel.c \
lib/fuse_mt.c \
lib/fuse_opt.c \
lib/fuse_session.c \
lib/fuse_signals.c \
lib/helper.c \
lib/mount.c
OBJS = $(SRC:lib/%.c=build/%.o)
DEPS = $(SRC:lib/%.c=build/%.d)
CFLAGS += \
$(OPTS) \
$(DEBUG_FLAGS) \
-Wall \
-pipe \
'-D_FILE_OFFSET_BITS=64' \
'-D_REENTRANT' \
'-DFUSE_USE_VERSION=29' \
'-DFUSERMOUNT_DIR="/usr/local/bin"' \
'-DPACKAGE_VERSION=$(VERSION)' \
-Iinclude \
-Ibuild \
-MMD
LDFLAGS += \
-lrt \
-pthread
all: build/libfuse.a
build/config.h: build/stamp
ecfd/build | tee build/config.h
build/stamp:
mkdir -p build
touch $@
objects: build/config.h
$(MAKE) $(OBJS)
build/libfuse.a: objects
ar rcs build/libfuse.a $(OBJS)
build/mergerfs-mount: build/config.h util/fusermount.c lib/mount_util.c
$(CC) $(CFLAGS) -Ilib -o mergerfs-mount util/fusermount.c lib/mount_util.c
build/mount.mergerfs: build/libfuse.a util/mount.fuse.c
$(CC) $(CFLAGS) -o mount.mergerfs util/mount.fuse.c build/libfuse.a $(LDFLAGS)
build/%.o: lib/%.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -rf build
distclean: clean
install: build/mergerfs-mount build/mount.mergerfs
install -D build/mergerfs-mount "$(DESTDIR)$(BINDIR)/mergerfs-mount"
chown root:root "$(DESTDIR)$(BINDIR)/mergerfs-mount"
chmod u+s "$(DESTDIR)$(BINDIR)/mergerfs-mount"
install -D build/mount.mergerfs "$(DESTDIR)$(SBINDIR)/mount.mergerfs"
.PHONY: objects
-include $(DEPS)
+303
View File
@@ -0,0 +1,303 @@
What is new in 2.9
- Add "zero copy" support for kernel 2.6.35 or newer
- Make maximum background requests tunable on kernel 2.6.32 or newer
- Require --no-canonicalize in (u)mount (util-linux version 2.18 or
newer) to fix security problems with fusermount
- Use dynamically sized hash tables in high level library
- Memory use of filesystem daemon can shrink more easily
- Add "auto_unmount" option
- Add "remember" option
- Add man pages for fusermount, mount.fuse and ulockmgr_server
- API changes:
o Introduce "store" and "retrieve" for accessing kernel buffers on
kernel 2.6.36 or newer
o Introduce abstract buffer for zero copy operations
o Allow path calculation to be omitted on certain operations
o Allow batching forget requests
o Add "flock" method
o Add support for ioctl on directories
o Add delete notification
o Add fallocate operation (linux kernel 3.5 or newer)
- Bug fixes and small improvements
============================================================================
What is new in 2.8
- More scalable directory tree locking
- Atomic open(O_TRUNC) support
- Support big write requests on kernels 2.6.26 and newer
- Out-of-tree fuse module removed
- Better NFS exporting support
- New ioctl and poll requests
- New CUSE (Character Device in Userspace) interface
- Allow umask processing in userspace
- Added cache invalidation notifications
- Bugfixes and small improvements
============================================================================
What is new in 2.7
- Stacking support for the high level API
- Add filename charset conversion module
- Improved mounting
============================================================================
What is new in 2.6
- Improved read characteristics (asynchronous reads)
- Support for aborting filesystem connection
- POSIX file locking support
- Request interruption support
- Building module for Linux kernels earlier than 2.6.9 not supported
- Allow block device based filesystems to support swap files
- Several bugs fixed, including a rare system hang on SMP
============================================================================
What is new in 2.5
- Merge library part of FreeBSD port
- New atomic create+open, access and ftruncate operations
- On filesystems implementing the new create+open operation, and
running on Linux kernels 2.6.15 or later, the 'cp' operation will
work correctly when copying read-only files.
- New option parsing interface added to the library
- Lots of minor improvements and fixes
============================================================================
What is new in 2.4
- Simplify device opening. Now '/dev/fuse' is a requirement
- Allow module auto-loading if user has access to '/dev/fuse'
- Allow mounting over a regular file for unprivileged users
- Allow mounting of arbitrary FUSE filesystems from /etc/fstab
- New mount options: 'umask=M', 'uid=N', 'gid=N'
- Check for non-empty mountpoint, and refuse mount by default. New
mount option: 'nonempty'
- Low level (inode based) API added
- Allow 'direct_io' and 'keep_cache' options to be set on a
case-by-case basis on open.
- Add 'attr_timeout' and 'entry_timeout' mount options to the
high-level library. Until now these timeouts were fixed at 1 sec.
- Some bugfixes
============================================================================
What is new in 2.3
- Add new directory related operations: opendir(), readdir(),
releasedir() and fsyncdir()
- Add init() and destroy() operations which are called before the
event loop is started and after it has exited
- Update kernel ABI so that on dual architectures (e.g. AMD64) 32bit
binaries work under a 64bit kernel
- Bugfixes
============================================================================
What is new in 2.2
Userspace changes:
- Add fuse_file_info structure to file operations, this allows the
filesystem to return a file handle in open() which is passed to
read(), write(), flush(), fsync() and release().
- Add source compatibility with 2.1 and 1.4 releases
- Binary compatibility with 2.1 release is retained
Kernel changes:
- Make requests interruptible. This prevents the filesystem to go
into an unbreakable deadlock with itself.
- Make readpages() synchronous. Asynchronous requests are deadlock
prone, since they cannot be interrupted (see above)
- Remove shared-writeable mapping support, which could deadlock the
machine
- Remove INVALIDATE userspace initiated request
- Update ABI to be independent of sizeof(long), so dual-size archs
don't cause problems
- Remove /sys/fs/fuse/version. Version checking is now done through
the fuse device
- Replace directory reading method on the kernel interface. Instead
of passing an open file descriptor to the kernel, send data through
the FUSE device, like all other operations.
============================================================================
What is new in 2.1
* Bug fixes
* Improved support for filesystems implementing a custom event-loop
* Add 'pkg-config' support
* Kernel module can be compiled separately
============================================================================
What is new in 1.9
* Lots of bugs fixed
* Minor modifications to the library API
* Improvements to the kernel/userspace interface
* Mounting by non-root made more secure
* Build shared library in addition to the static one
* Consolidated mount options
* Optimized reading under 2.6 kernels
* Direct I/O support
* Support file I/O on deleted files
* Extended attributes support
============================================================================
What is new in 1.3
* Thanks to user bugreports and stress testing with LTP and sfx-linux
a number of bugs were fixed, some quite serious.
* Fix compile problems with recent SuSE kernles
============================================================================
What is new in 1.2
* Fix mount problems on recent 2.6 kernels with SELinux enabled
* Fixed writing files lager than 2GBytes
* Other bugfixes
============================================================================
What is new in 1.1
* Support for the 2.6 kernels
* Support for exporting filesystem over NFS in 2.6 kernels
* Read efficiency improvements: read in 64k blocks instead of 4k
(Michael Grigoriev). Can be turned on with '-l' option of fusermount
* Lazy automatic unmount
* Added 'fsync()' VFS call to the FUSE interface
* Bugfixes
============================================================================
What is new in 1.0
* Cleanups and bugfixes
* Added 'release()' VFS call to the FUSE interface
* 64 bit file offsets (handling of > 4 GByte files)
* libfuse is now under LGPL
* New 'statfs' call (Mark Glines)
* Cleaned up mount procedure (mostly by Mark Glines)
NOTE: Binaries linked with with a previous version of libavfs may
not work with the new version of the fusermount program. In such
case recompile the program after installing the new libavfs library.
* Fix for problems under linux kernel 2.4.19
============================================================================
What is new in 0.95
* Optimized read/write operations. Raw throughput has increased to
about 60Mbyte/s on a Celeron/360
* Python bindings by Jeff Epler
* Perl bindings by Mark Glines
* Improved multithreaded operation
* Simplified library interface
* Bugfixes
============================================================================
What is new in 0.9:
* Everything
+33
View File
@@ -0,0 +1,33 @@
NFS exporting is supported in Linux kernels 2.6.27 or later.
You need to add an fsid=NNN option to /etc/exports to make exporting a
FUSE directory work.
Filesystem support
------------------
NFS exporting works to some extent on all fuse filesystems, but not
perfectly. This is due to the stateless nature of the protocol, the
server has no way of knowing whether the client is keeping a reference
to a file or not, and hence that file may be removed from the server's
cache. In that case there has to be a way to look up that object
using the inode number, otherwise an ESTALE error will be returned.
1) low-level interface
Filesystems need to implement special lookups for the names "." and
"..". The former may be requested on any inode, including
non-directories, while the latter is only requested for directories.
Otherwise these special lookups should behave identically to ordinary
lookups.
2) high-level interface
Because the high-level interface is path based, it is not possible to
delegate looking up by inode to the filesystem.
To work around this, currently a "noforget" option is provided, which
makes the library remember nodes forever. This will make the NFS
server happy, but also results in an ever growing memory footprint for
the filesystem. For this reason if the filesystem is large (or the
memory is small), then this option is not recommended.
+108
View File
@@ -0,0 +1,108 @@
libfuse
=======
Warning: unresolved security issue
----------------------------------
Be aware that FUSE has an unresolved security bug
([bug #15](https://github.com/libfuse/libfuse/issues/15)): the
permission check for accessing a cached directory is only done once
when the directory entry is first loaded into the cache. Subsequent
accesses will re-use the results of the first check, even if the
directory permissions have since changed, and even if the subsequent
access is made by a different user.
This bug needs to be fixed in the Linux kernel and has been known
since 2006 but unfortunately no fix has been applied yet. If you
depend on correct permission handling for FUSE file systems, the only
workaround is to completely disable caching of directory
entries. Alternatively, the severity of the bug can be somewhat
reduced by not using the `allow_other` mount option.
About
-----
FUSE (Filesystem in Userspace) is an interface for userspace programs
to export a filesystem to the Linux kernel. The FUSE project consists
of two components: the *fuse* kernel module (maintained in the regular
kernel repositories) and the *libfuse* userspace library (maintained
in this repository). libfuse provides the reference implementation
for communicating with the FUSE kernel module.
A FUSE file system is typically implemented as a standalone
application that links with libfuse. libfuse provides functions to
mount the file system, unmount it, read requests from the kernel, and
send responses back. libfuse offers two APIs: a "high-level",
synchronous API, and a "low-level" asynchronous API. In both cases,
incoming requests from the kernel are passed to the main program using
callbacks. When using the high-level API, the callbacks may work with
file names and paths instead of inodes, and processing of a request
finishes when the callback function returns. When using the low-level
API, the callbacks must work with inodes and responses must be sent
explicitly using a separate set of API functions.
Installation
------------
./configure
make -j8
make install
You may also need to add `/usr/local/lib` to `/etc/ld.so.conf` and/or
run *ldconfig*. If you're building from the git repository (instead of
using a release tarball), you also need to run `./makeconf.sh` to
create the `configure` script.
You'll also need a fuse kernel module (Linux kernels 2.6.14 or later
contain FUSE support).
For more details see the file `INSTALL`
Security implications
---------------------
If you run `make install`, the *fusermount* program is installed
set-user-id to root. This is done to allow normal users to mount
their own filesystem implementations.
There must however be some limitations, in order to prevent Bad User from
doing nasty things. Currently those limitations are:
- The user can only mount on a mountpoint, for which it has write
permission
- The mountpoint is not a sticky directory which isn't owned by the
user (like /tmp usually is)
- No other user (including root) can access the contents of the
mounted filesystem (though this can be relaxed by allowing the use
of the `allow_other` and `allow_root` mount options in `fuse.conf`)
Building your own filesystem
------------------------------
FUSE comes with several example file systems in the `examples`
directory. For example, the *fusexmp* example mirrors the contents of
the root directory under the mountpoint. Start from there and adapt
the code!
The documentation of the API functions and necessary callbacks is
mostly contained in the files `include/fuse.h` (for the high-level
API) and `include/fuse_lowlevel.h` (for the low-level API). An
autogenerated html version of the API is available in the `doc/html`
directory and at http://libfuse.github.io/doxygen.
Getting Help
------------
If you need help, please ask on the <fuse-devel@lists.sourceforge.net>
mailing list (subscribe at
https://lists.sourceforge.net/lists/listinfo/fuse-devel).
Please report any bugs on the GitHub issue tracker at
https://github.com/libfuse/main/issues.
+17
View File
@@ -0,0 +1,17 @@
/*
ISC License
Copyright (c) 2018, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+16
View File
@@ -0,0 +1,16 @@
# ecfd: embeddable C feature discovery
This is a simple script and set of tests to help with what would traditionally be the `configure` step of most C/C++. It is intended to be simple to be embedded into a project and only depends on the C compiler and /bin/sh.
## USAGE
First copy `ecfd` into your project. Next simply call the build script which will run the tests and output a `config.` style file to `stdout`. Compile errors will output to `stderr` which can be used to understand why they aren't working.
```
$ ./ecfd/build > include/config.h
```
## TESTS
Each test is in a single module. The build script will try to compile each module and on success will execute the program. If anything is printed to `stdout` it will be appended to the `#define` printed to the build script's `stdout`. If the compilation fails nothing will be printed. Look at the tests directory for examples.
+32
View File
@@ -0,0 +1,32 @@
#!/bin/sh
PWD=$(pwd)
BASEPATH="${PWD}/${0%/*}"
CC=${CC:-cc}
OUTPUT="/dev/null"
echo "#ifndef CONFIG_H_INCLUDED"
echo "#define CONFIG_H_INCLUDED"
echo
IFS=
for file in "${BASEPATH}/tests/"*.c
do
binary="${file%.c}"
basename=$(basename ${binary})
${CC} -o "${binary}" "${file}" 1>&2
if [ $? -eq 0 ]; then
STDOUT=$(${binary})
if [ "${STDOUT}" != "" ]; then
echo "#define ${basename} ${STDOUT}"
else
echo "#define ${basename}"
fi
rm -f "${binary}"
fi
done
echo
echo "#endif"
+10
View File
@@ -0,0 +1,10 @@
#include <sys/types.h>
#include <unistd.h>
int
main(void)
{
(void)fork;
return 0;
}
+11
View File
@@ -0,0 +1,11 @@
#define _GNU_SOURCE
#include <fcntl.h>
int
main(int argc,
char *argv[])
{
(void)splice;
return 0;
}
@@ -0,0 +1,14 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int
main(int argc,
char *argv[])
{
struct stat st;
(void)st.st_atim;
return 0;
}
+11
View File
@@ -0,0 +1,11 @@
#include <fcntl.h>
#include <sys/stat.h>
int
main(int argc,
char *argv[])
{
(void)utimensat;
return 0;
}
+12
View File
@@ -0,0 +1,12 @@
#define _GNU_SOURCE
#include <fcntl.h>
#include <sys/uio.h>
int
main(int argc,
char *argv[])
{
(void)vmsplice;
return 0;
}
+4
View File
@@ -0,0 +1,4 @@
#pragma once
#define STATIC_ASSERT(condition) \
((void)sizeof(char[1 - 2*!(condition)]))
+11
View File
@@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: fuse
Description: Filesystem in Userspace
Version: @VERSION@
Libs: -L${libdir} -lfuse -pthread
Libs.private: @libfuse_libs@
Cflags: -I${includedir}/fuse -D_FILE_OFFSET_BITS=64
+17
View File
@@ -0,0 +1,17 @@
## Process this file with automake to produce Makefile.in
fuseincludedir=$(includedir)/fuse
fuseinclude_HEADERS = \
fuse.h \
fuse_compat.h \
fuse_common.h \
fuse_common_compat.h \
fuse_lowlevel.h \
fuse_lowlevel_compat.h \
fuse_opt.h \
cuse_lowlevel.h
include_HEADERS = old/fuse.h ulockmgr.h
noinst_HEADERS = fuse_kernel.h
+87
View File
@@ -0,0 +1,87 @@
/*
CUSE: Character device in Userspace
Copyright (C) 2008-2009 SUSE Linux Products GmbH
Copyright (C) 2008-2009 Tejun Heo <tj@kernel.org>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
Read example/cusexmp.c for usages.
*/
#ifndef _CUSE_LOWLEVEL_H_
#define _CUSE_LOWLEVEL_H_
#ifndef FUSE_USE_VERSION
#define FUSE_USE_VERSION 29
#endif
#include "fuse_lowlevel.h"
#include <fcntl.h>
#include <sys/types.h>
#include <sys/uio.h>
#ifdef __cplusplus
extern "C" {
#endif
#define CUSE_UNRESTRICTED_IOCTL (1 << 0) /* use unrestricted ioctl */
struct fuse_session;
struct cuse_info {
unsigned dev_major;
unsigned dev_minor;
unsigned dev_info_argc;
const char **dev_info_argv;
unsigned flags;
};
/*
* Most ops behave almost identically to the matching fuse_lowlevel
* ops except that they don't take @ino.
*
* init_done : called after initialization is complete
* read/write : always direct IO, simultaneous operations allowed
* ioctl : might be in unrestricted mode depending on ci->flags
*/
struct cuse_lowlevel_ops {
void (*init) (void *userdata, struct fuse_conn_info *conn);
void (*init_done) (void *userdata);
void (*destroy) (void *userdata);
void (*open) (fuse_req_t req, struct fuse_file_info *fi);
void (*read) (fuse_req_t req, size_t size, off_t off,
struct fuse_file_info *fi);
void (*write) (fuse_req_t req, const char *buf, size_t size, off_t off,
struct fuse_file_info *fi);
void (*flush) (fuse_req_t req, struct fuse_file_info *fi);
void (*release) (fuse_req_t req, struct fuse_file_info *fi);
void (*fsync) (fuse_req_t req, int datasync, struct fuse_file_info *fi);
void (*ioctl) (fuse_req_t req, int cmd, void *arg,
struct fuse_file_info *fi, unsigned int flags,
const void *in_buf, size_t in_bufsz, size_t out_bufsz);
void (*poll) (fuse_req_t req, struct fuse_file_info *fi,
struct fuse_pollhandle *ph);
};
struct fuse_session *cuse_lowlevel_new(struct fuse_args *args,
const struct cuse_info *ci,
const struct cuse_lowlevel_ops *clop,
void *userdata);
struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[],
const struct cuse_info *ci,
const struct cuse_lowlevel_ops *clop,
int *multithreaded, void *userdata);
void cuse_lowlevel_teardown(struct fuse_session *se);
int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci,
const struct cuse_lowlevel_ops *clop, void *userdata);
#ifdef __cplusplus
}
#endif
#endif /* _CUSE_LOWLEVEL_H_ */
File diff suppressed because it is too large Load Diff
+520
View File
@@ -0,0 +1,520 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
/** @file */
#if !defined(_FUSE_H_) && !defined(_FUSE_LOWLEVEL_H_)
#error "Never include <fuse_common.h> directly; use <fuse.h> or <fuse_lowlevel.h> instead."
#endif
#ifndef _FUSE_COMMON_H_
#define _FUSE_COMMON_H_
#include "fuse_opt.h"
#include <stdint.h>
#include <sys/types.h>
/** Major version of FUSE library interface */
#define FUSE_MAJOR_VERSION 2
/** Minor version of FUSE library interface */
#define FUSE_MINOR_VERSION 9
#define FUSE_MAKE_VERSION(maj, min) ((maj) * 10 + (min))
#define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION)
/* This interface uses 64 bit off_t */
#if _FILE_OFFSET_BITS != 64
#error Please add -D_FILE_OFFSET_BITS=64 to your compile flags!
#endif
#define FUSE_DEFAULT_MAX_PAGES_PER_REQ 32
#define FUSE_MAX_MAX_PAGES 256
#ifdef __cplusplus
extern "C" {
#endif
/**
* Information about open files
*
* Changed in version 2.5
*/
struct
fuse_file_info
{
/** Open flags. Available in open() and release() */
int flags;
/** In case of a write operation indicates if this was caused by a
writepage */
uint32_t writepage : 1;
/** Can be filled in by open, to use direct I/O on this file.
Introduced in version 2.4 */
uint32_t direct_io : 1;
/** Can be filled in by open, to indicate, that cached file data
need not be invalidated. Introduced in version 2.4 */
uint32_t keep_cache : 1;
/** Indicates a flush operation. Set in flush operation, also
maybe set in highlevel lock operation and lowlevel release
operation. Introduced in version 2.6 */
uint32_t flush : 1;
/** Can be filled in by open, to indicate that the file is not
seekable. Introduced in version 2.8 */
uint32_t nonseekable : 1;
/* Indicates that flock locks for this file should be
released. If set, lock_owner shall contain a valid value.
May only be set in ->release(). Introduced in version
2.9 */
uint32_t flock_release : 1;
/* Requests the kernel to cache entries returned by readdir */
uint32_t cache_readdir : 1;
uint32_t auto_cache : 1;
/** Padding. Do not use*/
uint32_t padding : 24;
/** File handle. May be filled in by filesystem in open().
Available in all other file operations */
uint64_t fh;
/** Lock owner id. Available in locking operations and flush */
uint64_t lock_owner;
};
/**
* Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want'
*
* FUSE_CAP_ASYNC_READ: filesystem supports asynchronous read requests
* FUSE_CAP_POSIX_LOCKS: filesystem supports "remote" locking
* FUSE_CAP_ATOMIC_O_TRUNC: filesystem handles the O_TRUNC open flag
* FUSE_CAP_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
* FUSE_CAP_BIG_WRITES: filesystem can handle write size larger than 4kB
* FUSE_CAP_DONT_MASK: don't apply umask to file mode on create operations
* FUSE_CAP_SPLICE_WRITE: ability to use splice() to write to the fuse device
* FUSE_CAP_SPLICE_MOVE: ability to move data to the fuse device with splice()
* FUSE_CAP_SPLICE_READ: ability to use splice() to read from the fuse device
* FUSE_CAP_IOCTL_DIR: ioctl support on directories
* FUSE_CAP_CACHE_SYMLINKS: cache READLINK responses
*/
#define FUSE_CAP_ASYNC_READ (1 << 0)
#define FUSE_CAP_POSIX_LOCKS (1 << 1)
#define FUSE_CAP_ATOMIC_O_TRUNC (1 << 3)
#define FUSE_CAP_EXPORT_SUPPORT (1 << 4)
#define FUSE_CAP_BIG_WRITES (1 << 5)
#define FUSE_CAP_DONT_MASK (1 << 6)
#define FUSE_CAP_SPLICE_WRITE (1 << 7)
#define FUSE_CAP_SPLICE_MOVE (1 << 8)
#define FUSE_CAP_SPLICE_READ (1 << 9)
#define FUSE_CAP_FLOCK_LOCKS (1 << 10)
#define FUSE_CAP_IOCTL_DIR (1 << 11)
#define FUSE_CAP_ASYNC_DIO (1 << 15)
#define FUSE_CAP_PARALLEL_DIROPS (1 << 18)
#define FUSE_CAP_POSIX_ACL (1 << 19)
#define FUSE_CAP_CACHE_SYMLINKS (1 << 20)
#define FUSE_CAP_MAX_PAGES (1 << 21)
/**
* Ioctl flags
*
* FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine
* FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed
* FUSE_IOCTL_RETRY: retry with new iovecs
* FUSE_IOCTL_DIR: is a directory
*
* FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs
*/
#define FUSE_IOCTL_COMPAT (1 << 0)
#define FUSE_IOCTL_UNRESTRICTED (1 << 1)
#define FUSE_IOCTL_RETRY (1 << 2)
#define FUSE_IOCTL_DIR (1 << 4)
#define FUSE_IOCTL_MAX_IOV 256
/**
* Connection information, passed to the ->init() method
*
* Some of the elements are read-write, these can be changed to
* indicate the value requested by the filesystem. The requested
* value must usually be smaller than the indicated value.
*/
struct fuse_conn_info {
/**
* Major version of the protocol (read-only)
*/
unsigned proto_major;
/**
* Minor version of the protocol (read-only)
*/
unsigned proto_minor;
/**
* Maximum size of the write buffer
*/
unsigned max_write;
/**
* Maximum readahead
*/
unsigned max_readahead;
/**
* Capability flags, that the kernel supports
*/
unsigned capable;
/**
* Capability flags, that the filesystem wants to enable
*/
unsigned want;
/**
* Maximum number of backgrounded requests
*/
unsigned max_background;
/**
* Kernel congestion threshold parameter
*/
unsigned congestion_threshold;
/**
* Max pages
*/
uint16_t max_pages;
/**
* For future use.
*/
unsigned reserved[22];
};
struct fuse_session;
struct fuse_chan;
struct fuse_pollhandle;
/**
* Create a FUSE mountpoint
*
* Returns a control file descriptor suitable for passing to
* fuse_new()
*
* @param mountpoint the mount point path
* @param args argument vector
* @return the communication channel on success, NULL on failure
*/
struct fuse_chan *fuse_mount(const char *mountpoint,
struct fuse_args *args);
/**
* Umount a FUSE mountpoint
*
* @param mountpoint the mount point path
* @param ch the communication channel
*/
void fuse_unmount(const char *mountpoint, struct fuse_chan *ch);
/**
* Parse common options
*
* The following options are parsed:
*
* '-f' foreground
* '-d' '-odebug' foreground, but keep the debug option
* '-s' single threaded
* '-h' '--help' help
* '-ho' help without header
* '-ofsname=..' file system name, if not present, then set to the program
* name
*
* All parameters may be NULL
*
* @param args argument vector
* @param mountpoint the returned mountpoint, should be freed after use
* @param multithreaded set to 1 unless the '-s' option is present
* @param foreground set to 1 if one of the relevant options is present
* @return 0 on success, -1 on failure
*/
int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint,
int *multithreaded, int *foreground);
/**
* Go into the background
*
* @param foreground if true, stay in the foreground
* @return 0 on success, -1 on failure
*/
int fuse_daemonize(int foreground);
/**
* Get the version of the library
*
* @return the version
*/
int fuse_version(void);
/**
* Destroy poll handle
*
* @param ph the poll handle
*/
void fuse_pollhandle_destroy(struct fuse_pollhandle *ph);
/* ----------------------------------------------------------- *
* Data buffer *
* ----------------------------------------------------------- */
/**
* Buffer flags
*/
enum fuse_buf_flags {
/**
* Buffer contains a file descriptor
*
* If this flag is set, the .fd field is valid, otherwise the
* .mem fields is valid.
*/
FUSE_BUF_IS_FD = (1 << 1),
/**
* Seek on the file descriptor
*
* If this flag is set then the .pos field is valid and is
* used to seek to the given offset before performing
* operation on file descriptor.
*/
FUSE_BUF_FD_SEEK = (1 << 2),
/**
* Retry operation on file descriptor
*
* If this flag is set then retry operation on file descriptor
* until .size bytes have been copied or an error or EOF is
* detected.
*/
FUSE_BUF_FD_RETRY = (1 << 3),
};
/**
* Buffer copy flags
*/
enum fuse_buf_copy_flags {
/**
* Don't use splice(2)
*
* Always fall back to using read and write instead of
* splice(2) to copy data from one file descriptor to another.
*
* If this flag is not set, then only fall back if splice is
* unavailable.
*/
FUSE_BUF_NO_SPLICE = (1 << 1),
/**
* Force splice
*
* Always use splice(2) to copy data from one file descriptor
* to another. If splice is not available, return -EINVAL.
*/
FUSE_BUF_FORCE_SPLICE = (1 << 2),
/**
* Try to move data with splice.
*
* If splice is used, try to move pages from the source to the
* destination instead of copying. See documentation of
* SPLICE_F_MOVE in splice(2) man page.
*/
FUSE_BUF_SPLICE_MOVE = (1 << 3),
/**
* Don't block on the pipe when copying data with splice
*
* Makes the operations on the pipe non-blocking (if the pipe
* is full or empty). See SPLICE_F_NONBLOCK in the splice(2)
* man page.
*/
FUSE_BUF_SPLICE_NONBLOCK= (1 << 4),
};
/**
* Single data buffer
*
* Generic data buffer for I/O, extended attributes, etc... Data may
* be supplied as a memory pointer or as a file descriptor
*/
struct fuse_buf {
/**
* Size of data in bytes
*/
size_t size;
/**
* Buffer flags
*/
enum fuse_buf_flags flags;
/**
* Memory pointer
*
* Used unless FUSE_BUF_IS_FD flag is set.
*/
void *mem;
/**
* File descriptor
*
* Used if FUSE_BUF_IS_FD flag is set.
*/
int fd;
/**
* File position
*
* Used if FUSE_BUF_FD_SEEK flag is set.
*/
off_t pos;
};
/**
* Data buffer vector
*
* An array of data buffers, each containing a memory pointer or a
* file descriptor.
*
* Allocate dynamically to add more than one buffer.
*/
struct fuse_bufvec {
/**
* Number of buffers in the array
*/
size_t count;
/**
* Index of current buffer within the array
*/
size_t idx;
/**
* Current offset within the current buffer
*/
size_t off;
/**
* Array of buffers
*/
struct fuse_buf buf[1];
};
/* Initialize bufvec with a single buffer of given size */
#define FUSE_BUFVEC_INIT(size__) \
((struct fuse_bufvec) { \
/* .count= */ 1, \
/* .idx = */ 0, \
/* .off = */ 0, \
/* .buf = */ { /* [0] = */ { \
/* .size = */ (size__), \
/* .flags = */ (enum fuse_buf_flags) 0, \
/* .mem = */ NULL, \
/* .fd = */ -1, \
/* .pos = */ 0, \
} } \
} )
/**
* Get total size of data in a fuse buffer vector
*
* @param bufv buffer vector
* @return size of data
*/
size_t fuse_buf_size(const struct fuse_bufvec *bufv);
/**
* Copy data from one buffer vector to another
*
* @param dst destination buffer vector
* @param src source buffer vector
* @param flags flags controlling the copy
* @return actual number of bytes copied or -errno on error
*/
ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src,
enum fuse_buf_copy_flags flags);
/* ----------------------------------------------------------- *
* Signal handling *
* ----------------------------------------------------------- */
/**
* Exit session on HUP, TERM and INT signals and ignore PIPE signal
*
* Stores session in a global variable. May only be called once per
* process until fuse_remove_signal_handlers() is called.
*
* @param se the session to exit
* @return 0 on success, -1 on failure
*/
int fuse_set_signal_handlers(struct fuse_session *se);
/**
* Restore default signal handlers
*
* Resets global session. After this fuse_set_signal_handlers() may
* be called again.
*
* @param se the same session as given in fuse_set_signal_handlers()
*/
void fuse_remove_signal_handlers(struct fuse_session *se);
/* ----------------------------------------------------------- *
* Compatibility stuff *
* ----------------------------------------------------------- */
#if FUSE_USE_VERSION < 26
# ifdef __FreeBSD__
# if FUSE_USE_VERSION < 25
# error On FreeBSD API version 25 or greater must be used
# endif
# endif
# include "fuse_common_compat.h"
# undef FUSE_MINOR_VERSION
# undef fuse_main
# define fuse_unmount fuse_unmount_compat22
# if FUSE_USE_VERSION == 25
# define FUSE_MINOR_VERSION 5
# define fuse_mount fuse_mount_compat25
# elif FUSE_USE_VERSION == 24 || FUSE_USE_VERSION == 22
# define FUSE_MINOR_VERSION 4
# define fuse_mount fuse_mount_compat22
# elif FUSE_USE_VERSION == 21
# define FUSE_MINOR_VERSION 1
# define fuse_mount fuse_mount_compat22
# elif FUSE_USE_VERSION == 11
# warning Compatibility with API version 11 is deprecated
# undef FUSE_MAJOR_VERSION
# define FUSE_MAJOR_VERSION 1
# define FUSE_MINOR_VERSION 1
# define fuse_mount fuse_mount_compat1
# else
# error Compatibility with API version other than 21, 22, 24, 25 and 11 not supported
# endif
#endif
#ifdef __cplusplus
}
#endif
#endif /* _FUSE_COMMON_H_ */
+26
View File
@@ -0,0 +1,26 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
/* these definitions provide source compatibility to prior versions.
Do not include this file directly! */
struct fuse_file_info_compat {
int flags;
unsigned long fh;
int writepage;
unsigned int direct_io : 1;
unsigned int keep_cache : 1;
};
int fuse_mount_compat25(const char *mountpoint, struct fuse_args *args);
int fuse_mount_compat22(const char *mountpoint, const char *opts);
int fuse_mount_compat1(const char *mountpoint, const char *args[]);
void fuse_unmount_compat22(const char *mountpoint);
+201
View File
@@ -0,0 +1,201 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
/* these definitions provide source compatibility to prior versions.
Do not include this file directly! */
struct fuse_operations_compat25 {
int (*getattr) (const char *, struct stat *);
int (*readlink) (const char *, char *, size_t);
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
int (*mknod) (const char *, mode_t, dev_t);
int (*mkdir) (const char *, mode_t);
int (*unlink) (const char *);
int (*rmdir) (const char *);
int (*symlink) (const char *, const char *);
int (*rename) (const char *, const char *);
int (*link) (const char *, const char *);
int (*chmod) (const char *, mode_t);
int (*chown) (const char *, uid_t, gid_t);
int (*truncate) (const char *, off_t);
int (*utime) (const char *, struct utimbuf *);
int (*open) (const char *, struct fuse_file_info *);
int (*read) (const char *, char *, size_t, off_t,
struct fuse_file_info *);
int (*write) (const char *, const char *, size_t, off_t,
struct fuse_file_info *);
int (*statfs) (const char *, struct statvfs *);
int (*flush) (const char *, struct fuse_file_info *);
int (*release) (const char *, struct fuse_file_info *);
int (*fsync) (const char *, int, struct fuse_file_info *);
int (*setxattr) (const char *, const char *, const char *, size_t, int);
int (*getxattr) (const char *, const char *, char *, size_t);
int (*listxattr) (const char *, char *, size_t);
int (*removexattr) (const char *, const char *);
int (*opendir) (const char *, struct fuse_file_info *);
int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t,
struct fuse_file_info *);
int (*releasedir) (const char *, struct fuse_file_info *);
int (*fsyncdir) (const char *, int, struct fuse_file_info *);
void *(*init) (void);
void (*destroy) (void *);
int (*access) (const char *, int);
int (*create) (const char *, mode_t, struct fuse_file_info *);
int (*ftruncate) (const char *, off_t, struct fuse_file_info *);
int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *);
};
struct fuse *fuse_new_compat25(int fd, struct fuse_args *args,
const struct fuse_operations_compat25 *op,
size_t op_size);
int fuse_main_real_compat25(int argc, char *argv[],
const struct fuse_operations_compat25 *op,
size_t op_size);
struct fuse *fuse_setup_compat25(int argc, char *argv[],
const struct fuse_operations_compat25 *op,
size_t op_size, char **mountpoint,
int *multithreaded, int *fd);
void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint);
#if !defined(__FreeBSD__) && !defined(__NetBSD__)
#include <sys/statfs.h>
struct fuse_operations_compat22 {
int (*getattr) (const char *, struct stat *);
int (*readlink) (const char *, char *, size_t);
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
int (*mknod) (const char *, mode_t, dev_t);
int (*mkdir) (const char *, mode_t);
int (*unlink) (const char *);
int (*rmdir) (const char *);
int (*symlink) (const char *, const char *);
int (*rename) (const char *, const char *);
int (*link) (const char *, const char *);
int (*chmod) (const char *, mode_t);
int (*chown) (const char *, uid_t, gid_t);
int (*truncate) (const char *, off_t);
int (*utime) (const char *, struct utimbuf *);
int (*open) (const char *, struct fuse_file_info_compat *);
int (*read) (const char *, char *, size_t, off_t,
struct fuse_file_info_compat *);
int (*write) (const char *, const char *, size_t, off_t,
struct fuse_file_info_compat *);
int (*statfs) (const char *, struct statfs *);
int (*flush) (const char *, struct fuse_file_info_compat *);
int (*release) (const char *, struct fuse_file_info_compat *);
int (*fsync) (const char *, int, struct fuse_file_info_compat *);
int (*setxattr) (const char *, const char *, const char *, size_t, int);
int (*getxattr) (const char *, const char *, char *, size_t);
int (*listxattr) (const char *, char *, size_t);
int (*removexattr) (const char *, const char *);
int (*opendir) (const char *, struct fuse_file_info_compat *);
int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t,
struct fuse_file_info_compat *);
int (*releasedir) (const char *, struct fuse_file_info_compat *);
int (*fsyncdir) (const char *, int, struct fuse_file_info_compat *);
void *(*init) (void);
void (*destroy) (void *);
};
struct fuse *fuse_new_compat22(int fd, const char *opts,
const struct fuse_operations_compat22 *op,
size_t op_size);
struct fuse *fuse_setup_compat22(int argc, char *argv[],
const struct fuse_operations_compat22 *op,
size_t op_size, char **mountpoint,
int *multithreaded, int *fd);
int fuse_main_real_compat22(int argc, char *argv[],
const struct fuse_operations_compat22 *op,
size_t op_size);
typedef int (*fuse_dirfil_t_compat) (fuse_dirh_t h, const char *name, int type);
struct fuse_operations_compat2 {
int (*getattr) (const char *, struct stat *);
int (*readlink) (const char *, char *, size_t);
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t_compat);
int (*mknod) (const char *, mode_t, dev_t);
int (*mkdir) (const char *, mode_t);
int (*unlink) (const char *);
int (*rmdir) (const char *);
int (*symlink) (const char *, const char *);
int (*rename) (const char *, const char *);
int (*link) (const char *, const char *);
int (*chmod) (const char *, mode_t);
int (*chown) (const char *, uid_t, gid_t);
int (*truncate) (const char *, off_t);
int (*utime) (const char *, struct utimbuf *);
int (*open) (const char *, int);
int (*read) (const char *, char *, size_t, off_t);
int (*write) (const char *, const char *, size_t, off_t);
int (*statfs) (const char *, struct statfs *);
int (*flush) (const char *);
int (*release) (const char *, int);
int (*fsync) (const char *, int);
int (*setxattr) (const char *, const char *, const char *,
size_t, int);
int (*getxattr) (const char *, const char *, char *, size_t);
int (*listxattr) (const char *, char *, size_t);
int (*removexattr) (const char *, const char *);
};
int fuse_main_compat2(int argc, char *argv[],
const struct fuse_operations_compat2 *op);
struct fuse *fuse_new_compat2(int fd, const char *opts,
const struct fuse_operations_compat2 *op);
struct fuse *fuse_setup_compat2(int argc, char *argv[],
const struct fuse_operations_compat2 *op,
char **mountpoint, int *multithreaded, int *fd);
struct fuse_statfs_compat1 {
long block_size;
long blocks;
long blocks_free;
long files;
long files_free;
long namelen;
};
struct fuse_operations_compat1 {
int (*getattr) (const char *, struct stat *);
int (*readlink) (const char *, char *, size_t);
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t_compat);
int (*mknod) (const char *, mode_t, dev_t);
int (*mkdir) (const char *, mode_t);
int (*unlink) (const char *);
int (*rmdir) (const char *);
int (*symlink) (const char *, const char *);
int (*rename) (const char *, const char *);
int (*link) (const char *, const char *);
int (*chmod) (const char *, mode_t);
int (*chown) (const char *, uid_t, gid_t);
int (*truncate) (const char *, off_t);
int (*utime) (const char *, struct utimbuf *);
int (*open) (const char *, int);
int (*read) (const char *, char *, size_t, off_t);
int (*write) (const char *, const char *, size_t, off_t);
int (*statfs) (struct fuse_statfs_compat1 *);
int (*release) (const char *, int);
int (*fsync) (const char *, int);
};
#define FUSE_DEBUG_COMPAT1 (1 << 1)
struct fuse *fuse_new_compat1(int fd, int flags,
const struct fuse_operations_compat1 *op);
void fuse_main_compat1(int argc, char *argv[],
const struct fuse_operations_compat1 *op);
#endif /* __FreeBSD__ || __NetBSD__ */
+825
View File
@@ -0,0 +1,825 @@
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) */
/*
This file defines the kernel interface of FUSE
Copyright (C) 2001-2008 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
This -- and only this -- header file may also be distributed under
the terms of the BSD Licence as follows:
Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
*/
/*
* This file defines the kernel interface of FUSE
*
* Protocol changelog:
*
* 7.9:
* - new fuse_getattr_in input argument of GETATTR
* - add lk_flags in fuse_lk_in
* - add lock_owner field to fuse_setattr_in, fuse_read_in and fuse_write_in
* - add blksize field to fuse_attr
* - add file flags field to fuse_read_in and fuse_write_in
*
* 7.10
* - add nonseekable open flag
*
* 7.11
* - add IOCTL message
* - add unsolicited notification support
* - add POLL message and NOTIFY_POLL notification
*
* 7.12
* - add umask flag to input argument of open, mknod and mkdir
* - add notification messages for invalidation of inodes and
* directory entries
*
* 7.13
* - make max number of background requests and congestion threshold
* tunables
*
* 7.14
* - add splice support to fuse device
*
* 7.15
* - add store notify
* - add retrieve notify
*
* 7.16
* - add BATCH_FORGET request
* - FUSE_IOCTL_UNRESTRICTED shall now return with array of 'struct
* fuse_ioctl_iovec' instead of ambiguous 'struct iovec'
* - add FUSE_IOCTL_32BIT flag
*
* 7.17
* - add FUSE_FLOCK_LOCKS and FUSE_RELEASE_FLOCK_UNLOCK
*
* 7.18
* - add FUSE_IOCTL_DIR flag
* - add FUSE_NOTIFY_DELETE
*
* 7.19
* - add FUSE_FALLOCATE
*
* 7.20
* - add FUSE_AUTO_INVAL_DATA
*
* 7.21
* - add FUSE_READDIRPLUS
* - send the requested events in POLL request
*
* 7.22
* - add FUSE_ASYNC_DIO
*
* 7.23
* - add FUSE_WRITEBACK_CACHE
* - add time_gran to fuse_init_out
* - add reserved space to fuse_init_out
* - add FATTR_CTIME
* - add ctime and ctimensec to fuse_setattr_in
* - add FUSE_RENAME2 request
* - add FUSE_NO_OPEN_SUPPORT flag
*
* 7.24
* - add FUSE_LSEEK for SEEK_HOLE and SEEK_DATA support
*
* 7.25
* - add FUSE_PARALLEL_DIROPS
*
* 7.26
* - add FUSE_HANDLE_KILLPRIV
* - add FUSE_POSIX_ACL
*
* 7.27
* - add FUSE_ABORT_ERROR
*
* 7.28
* - add FUSE_COPY_FILE_RANGE
* - add FOPEN_CACHE_DIR
* - add FUSE_MAX_PAGES, add max_pages to init_out
* - add FUSE_CACHE_SYMLINKS
*
* 7.29
* - add FUSE_NO_OPENDIR_SUPPORT flag
*/
#ifndef _LINUX_FUSE_H
#define _LINUX_FUSE_H
#ifdef __KERNEL__
#include <linux/types.h>
#else
#include <stdint.h>
#endif
/*
* Version negotiation:
*
* Both the kernel and userspace send the version they support in the
* INIT request and reply respectively.
*
* If the major versions match then both shall use the smallest
* of the two minor versions for communication.
*
* If the kernel supports a larger major version, then userspace shall
* reply with the major version it supports, ignore the rest of the
* INIT message and expect a new INIT message from the kernel with a
* matching major version.
*
* If the library supports a larger major version, then it shall fall
* back to the major protocol version sent by the kernel for
* communication and reply with that major version (and an arbitrary
* supported minor version).
*/
/** Version number of this interface */
#define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */
#define FUSE_KERNEL_MINOR_VERSION 29
/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
/* Make sure all structures are padded to 64bit boundary, so 32bit
userspace works under 64bit kernels */
struct fuse_attr {
uint64_t ino;
uint64_t size;
uint64_t blocks;
uint64_t atime;
uint64_t mtime;
uint64_t ctime;
uint32_t atimensec;
uint32_t mtimensec;
uint32_t ctimensec;
uint32_t mode;
uint32_t nlink;
uint32_t uid;
uint32_t gid;
uint32_t rdev;
uint32_t blksize;
uint32_t padding;
};
struct fuse_kstatfs {
uint64_t blocks;
uint64_t bfree;
uint64_t bavail;
uint64_t files;
uint64_t ffree;
uint32_t bsize;
uint32_t namelen;
uint32_t frsize;
uint32_t padding;
uint32_t spare[6];
};
struct fuse_file_lock {
uint64_t start;
uint64_t end;
uint32_t type;
uint32_t pid; /* tgid */
};
/**
* Bitmasks for fuse_setattr_in.valid
*/
#define FATTR_MODE (1 << 0)
#define FATTR_UID (1 << 1)
#define FATTR_GID (1 << 2)
#define FATTR_SIZE (1 << 3)
#define FATTR_ATIME (1 << 4)
#define FATTR_MTIME (1 << 5)
#define FATTR_FH (1 << 6)
#define FATTR_ATIME_NOW (1 << 7)
#define FATTR_MTIME_NOW (1 << 8)
#define FATTR_LOCKOWNER (1 << 9)
#define FATTR_CTIME (1 << 10)
/**
* Flags returned by the OPEN request
*
* FOPEN_DIRECT_IO: bypass page cache for this open file
* FOPEN_KEEP_CACHE: don't invalidate the data cache on open
* FOPEN_NONSEEKABLE: the file is not seekable
* FOPEN_CACHE_DIR: allow caching this directory
*/
#define FOPEN_DIRECT_IO (1 << 0)
#define FOPEN_KEEP_CACHE (1 << 1)
#define FOPEN_NONSEEKABLE (1 << 2)
#define FOPEN_CACHE_DIR (1 << 3)
/**
* INIT request/reply flags
*
* FUSE_ASYNC_READ: asynchronous read requests
* FUSE_POSIX_LOCKS: remote locking for POSIX file locks
* FUSE_FILE_OPS: kernel sends file handle for fstat, etc... (not yet supported)
* FUSE_ATOMIC_O_TRUNC: handles the O_TRUNC open flag in the filesystem
* FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
* FUSE_BIG_WRITES: filesystem can handle write size larger than 4kB
* FUSE_DONT_MASK: don't apply umask to file mode on create operations
* FUSE_SPLICE_WRITE: kernel supports splice write on the device
* FUSE_SPLICE_MOVE: kernel supports splice move on the device
* FUSE_SPLICE_READ: kernel supports splice read on the device
* FUSE_FLOCK_LOCKS: remote locking for BSD style file locks
* FUSE_HAS_IOCTL_DIR: kernel supports ioctl on directories
* FUSE_AUTO_INVAL_DATA: automatically invalidate cached pages
* FUSE_DO_READDIRPLUS: do READDIRPLUS (READDIR+LOOKUP in one)
* FUSE_READDIRPLUS_AUTO: adaptive readdirplus
* FUSE_ASYNC_DIO: asynchronous direct I/O submission
* FUSE_WRITEBACK_CACHE: use writeback cache for buffered writes
* FUSE_NO_OPEN_SUPPORT: kernel supports zero-message opens
* FUSE_PARALLEL_DIROPS: allow parallel lookups and readdir
* FUSE_HANDLE_KILLPRIV: fs handles killing suid/sgid/cap on write/chown/trunc
* FUSE_POSIX_ACL: filesystem supports posix acls
* FUSE_ABORT_ERROR: reading the device after abort returns ECONNABORTED
* FUSE_MAX_PAGES: init_out.max_pages contains the max number of req pages
* FUSE_CACHE_SYMLINKS: cache READLINK responses
* FUSE_NO_OPENDIR_SUPPORT: kernel supports zero-message opendir
*/
#define FUSE_ASYNC_READ (1 << 0)
#define FUSE_POSIX_LOCKS (1 << 1)
#define FUSE_FILE_OPS (1 << 2)
#define FUSE_ATOMIC_O_TRUNC (1 << 3)
#define FUSE_EXPORT_SUPPORT (1 << 4)
#define FUSE_BIG_WRITES (1 << 5)
#define FUSE_DONT_MASK (1 << 6)
#define FUSE_SPLICE_WRITE (1 << 7)
#define FUSE_SPLICE_MOVE (1 << 8)
#define FUSE_SPLICE_READ (1 << 9)
#define FUSE_FLOCK_LOCKS (1 << 10)
#define FUSE_HAS_IOCTL_DIR (1 << 11)
#define FUSE_AUTO_INVAL_DATA (1 << 12)
#define FUSE_DO_READDIRPLUS (1 << 13)
#define FUSE_READDIRPLUS_AUTO (1 << 14)
#define FUSE_ASYNC_DIO (1 << 15)
#define FUSE_WRITEBACK_CACHE (1 << 16)
#define FUSE_NO_OPEN_SUPPORT (1 << 17)
#define FUSE_PARALLEL_DIROPS (1 << 18)
#define FUSE_HANDLE_KILLPRIV (1 << 19)
#define FUSE_POSIX_ACL (1 << 20)
#define FUSE_ABORT_ERROR (1 << 21)
#define FUSE_MAX_PAGES (1 << 22)
#define FUSE_CACHE_SYMLINKS (1 << 23)
#define FUSE_NO_OPENDIR_SUPPORT (1 << 24)
/**
* CUSE INIT request/reply flags
*
* CUSE_UNRESTRICTED_IOCTL: use unrestricted ioctl
*/
#define CUSE_UNRESTRICTED_IOCTL (1 << 0)
/**
* Release flags
*/
#define FUSE_RELEASE_FLUSH (1 << 0)
#define FUSE_RELEASE_FLOCK_UNLOCK (1 << 1)
/**
* Getattr flags
*/
#define FUSE_GETATTR_FH (1 << 0)
/**
* Lock flags
*/
#define FUSE_LK_FLOCK (1 << 0)
/**
* WRITE flags
*
* FUSE_WRITE_CACHE: delayed write from page cache, file handle is guessed
* FUSE_WRITE_LOCKOWNER: lock_owner field is valid
*/
#define FUSE_WRITE_CACHE (1 << 0)
#define FUSE_WRITE_LOCKOWNER (1 << 1)
/**
* Read flags
*/
#define FUSE_READ_LOCKOWNER (1 << 1)
/**
* Ioctl flags
*
* FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine
* FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed
* FUSE_IOCTL_RETRY: retry with new iovecs
* FUSE_IOCTL_32BIT: 32bit ioctl
* FUSE_IOCTL_DIR: is a directory
*
* FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs
*/
#define FUSE_IOCTL_COMPAT (1 << 0)
#define FUSE_IOCTL_UNRESTRICTED (1 << 1)
#define FUSE_IOCTL_RETRY (1 << 2)
#define FUSE_IOCTL_32BIT (1 << 3)
#define FUSE_IOCTL_DIR (1 << 4)
#define FUSE_IOCTL_MAX_IOV 256
/**
* Poll flags
*
* FUSE_POLL_SCHEDULE_NOTIFY: request poll notify
*/
#define FUSE_POLL_SCHEDULE_NOTIFY (1 << 0)
enum fuse_opcode {
FUSE_LOOKUP = 1,
FUSE_FORGET = 2, /* no reply */
FUSE_GETATTR = 3,
FUSE_SETATTR = 4,
FUSE_READLINK = 5,
FUSE_SYMLINK = 6,
FUSE_MKNOD = 8,
FUSE_MKDIR = 9,
FUSE_UNLINK = 10,
FUSE_RMDIR = 11,
FUSE_RENAME = 12,
FUSE_LINK = 13,
FUSE_OPEN = 14,
FUSE_READ = 15,
FUSE_WRITE = 16,
FUSE_STATFS = 17,
FUSE_RELEASE = 18,
FUSE_FSYNC = 20,
FUSE_SETXATTR = 21,
FUSE_GETXATTR = 22,
FUSE_LISTXATTR = 23,
FUSE_REMOVEXATTR = 24,
FUSE_FLUSH = 25,
FUSE_INIT = 26,
FUSE_OPENDIR = 27,
FUSE_READDIR = 28,
FUSE_RELEASEDIR = 29,
FUSE_FSYNCDIR = 30,
FUSE_GETLK = 31,
FUSE_SETLK = 32,
FUSE_SETLKW = 33,
FUSE_ACCESS = 34,
FUSE_CREATE = 35,
FUSE_INTERRUPT = 36,
FUSE_BMAP = 37,
FUSE_DESTROY = 38,
FUSE_IOCTL = 39,
FUSE_POLL = 40,
FUSE_NOTIFY_REPLY = 41,
FUSE_BATCH_FORGET = 42,
FUSE_FALLOCATE = 43,
FUSE_READDIRPLUS = 44,
FUSE_RENAME2 = 45,
FUSE_LSEEK = 46,
FUSE_COPY_FILE_RANGE = 47,
/* CUSE specific operations */
CUSE_INIT = 4096,
};
enum fuse_notify_code {
FUSE_NOTIFY_POLL = 1,
FUSE_NOTIFY_INVAL_INODE = 2,
FUSE_NOTIFY_INVAL_ENTRY = 3,
FUSE_NOTIFY_STORE = 4,
FUSE_NOTIFY_RETRIEVE = 5,
FUSE_NOTIFY_DELETE = 6,
FUSE_NOTIFY_CODE_MAX,
};
/* The read buffer is required to be at least 8k, but may be much larger */
#define FUSE_MIN_READ_BUFFER 8192
#define FUSE_COMPAT_ENTRY_OUT_SIZE 120
struct fuse_entry_out {
uint64_t nodeid; /* Inode ID */
uint64_t generation; /* Inode generation: nodeid:gen must
be unique for the fs's lifetime */
uint64_t entry_valid; /* Cache timeout for the name */
uint64_t attr_valid; /* Cache timeout for the attributes */
uint32_t entry_valid_nsec;
uint32_t attr_valid_nsec;
struct fuse_attr attr;
};
struct fuse_forget_in {
uint64_t nlookup;
};
struct fuse_forget_one {
uint64_t nodeid;
uint64_t nlookup;
};
struct fuse_batch_forget_in {
uint32_t count;
uint32_t dummy;
};
struct fuse_getattr_in {
uint32_t getattr_flags;
uint32_t dummy;
uint64_t fh;
};
#define FUSE_COMPAT_ATTR_OUT_SIZE 96
struct fuse_attr_out {
uint64_t attr_valid; /* Cache timeout for the attributes */
uint32_t attr_valid_nsec;
uint32_t dummy;
struct fuse_attr attr;
};
#define FUSE_COMPAT_MKNOD_IN_SIZE 8
struct fuse_mknod_in {
uint32_t mode;
uint32_t rdev;
uint32_t umask;
uint32_t padding;
};
struct fuse_mkdir_in {
uint32_t mode;
uint32_t umask;
};
struct fuse_rename_in {
uint64_t newdir;
};
struct fuse_rename2_in {
uint64_t newdir;
uint32_t flags;
uint32_t padding;
};
struct fuse_link_in {
uint64_t oldnodeid;
};
struct fuse_setattr_in {
uint32_t valid;
uint32_t padding;
uint64_t fh;
uint64_t size;
uint64_t lock_owner;
uint64_t atime;
uint64_t mtime;
uint64_t ctime;
uint32_t atimensec;
uint32_t mtimensec;
uint32_t ctimensec;
uint32_t mode;
uint32_t unused4;
uint32_t uid;
uint32_t gid;
uint32_t unused5;
};
struct fuse_open_in {
uint32_t flags;
uint32_t unused;
};
struct fuse_create_in {
uint32_t flags;
uint32_t mode;
uint32_t umask;
uint32_t padding;
};
struct fuse_open_out {
uint64_t fh;
uint32_t open_flags;
uint32_t padding;
};
struct fuse_release_in {
uint64_t fh;
uint32_t flags;
uint32_t release_flags;
uint64_t lock_owner;
};
struct fuse_flush_in {
uint64_t fh;
uint32_t unused;
uint32_t padding;
uint64_t lock_owner;
};
struct fuse_read_in {
uint64_t fh;
uint64_t offset;
uint32_t size;
uint32_t read_flags;
uint64_t lock_owner;
uint32_t flags;
uint32_t padding;
};
#define FUSE_COMPAT_WRITE_IN_SIZE 24
struct fuse_write_in {
uint64_t fh;
uint64_t offset;
uint32_t size;
uint32_t write_flags;
uint64_t lock_owner;
uint32_t flags;
uint32_t padding;
};
struct fuse_write_out {
uint32_t size;
uint32_t padding;
};
#define FUSE_COMPAT_STATFS_SIZE 48
struct fuse_statfs_out {
struct fuse_kstatfs st;
};
struct fuse_fsync_in {
uint64_t fh;
uint32_t fsync_flags;
uint32_t padding;
};
struct fuse_setxattr_in {
uint32_t size;
uint32_t flags;
};
struct fuse_getxattr_in {
uint32_t size;
uint32_t padding;
};
struct fuse_getxattr_out {
uint32_t size;
uint32_t padding;
};
struct fuse_lk_in {
uint64_t fh;
uint64_t owner;
struct fuse_file_lock lk;
uint32_t lk_flags;
uint32_t padding;
};
struct fuse_lk_out {
struct fuse_file_lock lk;
};
struct fuse_access_in {
uint32_t mask;
uint32_t padding;
};
struct fuse_init_in {
uint32_t major;
uint32_t minor;
uint32_t max_readahead;
uint32_t flags;
};
#define FUSE_COMPAT_INIT_OUT_SIZE 8
#define FUSE_COMPAT_22_INIT_OUT_SIZE 24
struct fuse_init_out {
uint32_t major;
uint32_t minor;
uint32_t max_readahead;
uint32_t flags;
uint16_t max_background;
uint16_t congestion_threshold;
uint32_t max_write;
uint32_t time_gran;
uint16_t max_pages;
uint16_t padding;
uint32_t unused[8];
};
#define CUSE_INIT_INFO_MAX 4096
struct cuse_init_in {
uint32_t major;
uint32_t minor;
uint32_t unused;
uint32_t flags;
};
struct cuse_init_out {
uint32_t major;
uint32_t minor;
uint32_t unused;
uint32_t flags;
uint32_t max_read;
uint32_t max_write;
uint32_t dev_major; /* chardev major */
uint32_t dev_minor; /* chardev minor */
uint32_t spare[10];
};
struct fuse_interrupt_in {
uint64_t unique;
};
struct fuse_bmap_in {
uint64_t block;
uint32_t blocksize;
uint32_t padding;
};
struct fuse_bmap_out {
uint64_t block;
};
struct fuse_ioctl_in {
uint64_t fh;
uint32_t flags;
uint32_t cmd;
uint64_t arg;
uint32_t in_size;
uint32_t out_size;
};
struct fuse_ioctl_iovec {
uint64_t base;
uint64_t len;
};
struct fuse_ioctl_out {
int32_t result;
uint32_t flags;
uint32_t in_iovs;
uint32_t out_iovs;
};
struct fuse_poll_in {
uint64_t fh;
uint64_t kh;
uint32_t flags;
uint32_t events;
};
struct fuse_poll_out {
uint32_t revents;
uint32_t padding;
};
struct fuse_notify_poll_wakeup_out {
uint64_t kh;
};
struct fuse_fallocate_in {
uint64_t fh;
uint64_t offset;
uint64_t length;
uint32_t mode;
uint32_t padding;
};
struct fuse_in_header {
uint32_t len;
uint32_t opcode;
uint64_t unique;
uint64_t nodeid;
uint32_t uid;
uint32_t gid;
uint32_t pid;
uint32_t padding;
};
struct fuse_out_header {
uint32_t len;
int32_t error;
uint64_t unique;
};
struct fuse_dirent {
uint64_t ino;
uint64_t off;
uint32_t namelen;
uint32_t type;
char name[];
};
#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
#define FUSE_DIRENT_ALIGN(x) \
(((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1))
#define FUSE_DIRENT_SIZE(d) \
FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
struct fuse_direntplus {
struct fuse_entry_out entry_out;
struct fuse_dirent dirent;
};
#define FUSE_NAME_OFFSET_DIRENTPLUS \
offsetof(struct fuse_direntplus, dirent.name)
#define FUSE_DIRENTPLUS_SIZE(d) \
FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET_DIRENTPLUS + (d)->dirent.namelen)
struct fuse_notify_inval_inode_out {
uint64_t ino;
int64_t off;
int64_t len;
};
struct fuse_notify_inval_entry_out {
uint64_t parent;
uint32_t namelen;
uint32_t padding;
};
struct fuse_notify_delete_out {
uint64_t parent;
uint64_t child;
uint32_t namelen;
uint32_t padding;
};
struct fuse_notify_store_out {
uint64_t nodeid;
uint64_t offset;
uint32_t size;
uint32_t padding;
};
struct fuse_notify_retrieve_out {
uint64_t notify_unique;
uint64_t nodeid;
uint64_t offset;
uint32_t size;
uint32_t padding;
};
/* Matches the size of fuse_write_in */
struct fuse_notify_retrieve_in {
uint64_t dummy1;
uint64_t offset;
uint32_t size;
uint32_t dummy2;
uint64_t dummy3;
uint64_t dummy4;
};
/* Device ioctls: */
#define FUSE_DEV_IOC_CLONE _IOR(229, 0, uint32_t)
struct fuse_lseek_in {
uint64_t fh;
uint64_t offset;
uint32_t whence;
uint32_t padding;
};
struct fuse_lseek_out {
uint64_t offset;
};
struct fuse_copy_file_range_in {
uint64_t fh_in;
uint64_t off_in;
uint64_t nodeid_out;
uint64_t fh_out;
uint64_t off_out;
uint64_t len;
uint64_t flags;
};
#endif /* _LINUX_FUSE_H */
File diff suppressed because it is too large Load Diff
+155
View File
@@ -0,0 +1,155 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
/* these definitions provide source compatibility to prior versions.
Do not include this file directly! */
struct fuse_lowlevel_ops_compat25 {
void (*init) (void *userdata);
void (*destroy) (void *userdata);
void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name);
void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup);
void (*getattr) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi);
void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr,
int to_set, struct fuse_file_info *fi);
void (*readlink) (fuse_req_t req, fuse_ino_t ino);
void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode, dev_t rdev);
void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode);
void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name);
void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name);
void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent,
const char *name);
void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name,
fuse_ino_t newparent, const char *newname);
void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
const char *newname);
void (*open) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi);
void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
struct fuse_file_info *fi);
void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf,
size_t size, off_t off, struct fuse_file_info *fi);
void (*flush) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi);
void (*release) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi);
void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync,
struct fuse_file_info *fi);
void (*opendir) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi);
void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
struct fuse_file_info *fi);
void (*releasedir) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi);
void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync,
struct fuse_file_info *fi);
void (*statfs) (fuse_req_t req);
void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
const char *value, size_t size, int flags);
void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
size_t size);
void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size);
void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name);
void (*access) (fuse_req_t req, fuse_ino_t ino, int mask);
void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode, struct fuse_file_info *fi);
};
struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args,
const struct fuse_lowlevel_ops_compat25 *op,
size_t op_size, void *userdata);
size_t fuse_dirent_size(size_t namelen);
char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf,
off_t off);
#if !defined(__FreeBSD__) && !defined(__NetBSD__)
#include <sys/statfs.h>
struct fuse_lowlevel_ops_compat {
void (*init) (void *userdata);
void (*destroy) (void *userdata);
void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name);
void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup);
void (*getattr) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info_compat *fi);
void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr,
int to_set, struct fuse_file_info_compat *fi);
void (*readlink) (fuse_req_t req, fuse_ino_t ino);
void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode, dev_t rdev);
void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode);
void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name);
void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name);
void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent,
const char *name);
void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name,
fuse_ino_t newparent, const char *newname);
void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
const char *newname);
void (*open) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info_compat *fi);
void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
struct fuse_file_info_compat *fi);
void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf,
size_t size, off_t off, struct fuse_file_info_compat *fi);
void (*flush) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info_compat *fi);
void (*release) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info_compat *fi);
void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync,
struct fuse_file_info_compat *fi);
void (*opendir) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info_compat *fi);
void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
struct fuse_file_info_compat *fi);
void (*releasedir) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info_compat *fi);
void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync,
struct fuse_file_info_compat *fi);
void (*statfs) (fuse_req_t req);
void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
const char *value, size_t size, int flags);
void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
size_t size);
void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size);
void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name);
void (*access) (fuse_req_t req, fuse_ino_t ino, int mask);
void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode, struct fuse_file_info_compat *fi);
};
int fuse_reply_statfs_compat(fuse_req_t req, const struct statfs *stbuf);
int fuse_reply_open_compat(fuse_req_t req,
const struct fuse_file_info_compat *fi);
struct fuse_session *fuse_lowlevel_new_compat(const char *opts,
const struct fuse_lowlevel_ops_compat *op,
size_t op_size, void *userdata);
#endif /* __FreeBSD__ || __NetBSD__ */
struct fuse_chan_ops_compat24 {
int (*receive)(struct fuse_chan *ch, char *buf, size_t size);
int (*send)(struct fuse_chan *ch, const struct iovec iov[],
size_t count);
void (*destroy)(struct fuse_chan *ch);
};
struct fuse_chan *fuse_chan_new_compat24(struct fuse_chan_ops_compat24 *op,
int fd, size_t bufsize, void *data);
int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size);
struct fuse_chan *fuse_kern_chan_new(int fd);
+270
View File
@@ -0,0 +1,270 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
#ifndef _FUSE_OPT_H_
#define _FUSE_OPT_H_
/** @file
*
* This file defines the option parsing interface of FUSE
*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* Option description
*
* This structure describes a single option, and action associated
* with it, in case it matches.
*
* More than one such match may occur, in which case the action for
* each match is executed.
*
* There are three possible actions in case of a match:
*
* i) An integer (int or unsigned) variable determined by 'offset' is
* set to 'value'
*
* ii) The processing function is called, with 'value' as the key
*
* iii) An integer (any) or string (char *) variable determined by
* 'offset' is set to the value of an option parameter
*
* 'offset' should normally be either set to
*
* - 'offsetof(struct foo, member)' actions i) and iii)
*
* - -1 action ii)
*
* The 'offsetof()' macro is defined in the <stddef.h> header.
*
* The template determines which options match, and also have an
* effect on the action. Normally the action is either i) or ii), but
* if a format is present in the template, then action iii) is
* performed.
*
* The types of templates are:
*
* 1) "-x", "-foo", "--foo", "--foo-bar", etc. These match only
* themselves. Invalid values are "--" and anything beginning
* with "-o"
*
* 2) "foo", "foo-bar", etc. These match "-ofoo", "-ofoo-bar" or
* the relevant option in a comma separated option list
*
* 3) "bar=", "--foo=", etc. These are variations of 1) and 2)
* which have a parameter
*
* 4) "bar=%s", "--foo=%lu", etc. Same matching as above but perform
* action iii).
*
* 5) "-x ", etc. Matches either "-xparam" or "-x param" as
* two separate arguments
*
* 6) "-x %s", etc. Combination of 4) and 5)
*
* If the format is "%s", memory is allocated for the string unlike
* with scanf().
*/
struct fuse_opt {
/** Matching template and optional parameter formatting */
const char *templ;
/**
* Offset of variable within 'data' parameter of fuse_opt_parse()
* or -1
*/
unsigned long offset;
/**
* Value to set the variable to, or to be passed as 'key' to the
* processing function. Ignored if template has a format
*/
int value;
};
/**
* Key option. In case of a match, the processing function will be
* called with the specified key.
*/
#define FUSE_OPT_KEY(templ, key) { templ, -1U, key }
/**
* Last option. An array of 'struct fuse_opt' must end with a NULL
* template value
*/
#define FUSE_OPT_END { NULL, 0, 0 }
/**
* Argument list
*/
struct fuse_args {
/** Argument count */
int argc;
/** Argument vector. NULL terminated */
char **argv;
/** Is 'argv' allocated? */
int allocated;
};
/**
* Initializer for 'struct fuse_args'
*/
#define FUSE_ARGS_INIT(argc, argv) { argc, argv, 0 }
/**
* Key value passed to the processing function if an option did not
* match any template
*/
#define FUSE_OPT_KEY_OPT -1
/**
* Key value passed to the processing function for all non-options
*
* Non-options are the arguments beginning with a character other than
* '-' or all arguments after the special '--' option
*/
#define FUSE_OPT_KEY_NONOPT -2
/**
* Special key value for options to keep
*
* Argument is not passed to processing function, but behave as if the
* processing function returned 1
*/
#define FUSE_OPT_KEY_KEEP -3
/**
* Special key value for options to discard
*
* Argument is not passed to processing function, but behave as if the
* processing function returned zero
*/
#define FUSE_OPT_KEY_DISCARD -4
/**
* Processing function
*
* This function is called if
* - option did not match any 'struct fuse_opt'
* - argument is a non-option
* - option did match and offset was set to -1
*
* The 'arg' parameter will always contain the whole argument or
* option including the parameter if exists. A two-argument option
* ("-x foo") is always converted to single argument option of the
* form "-xfoo" before this function is called.
*
* Options of the form '-ofoo' are passed to this function without the
* '-o' prefix.
*
* The return value of this function determines whether this argument
* is to be inserted into the output argument vector, or discarded.
*
* @param data is the user data passed to the fuse_opt_parse() function
* @param arg is the whole argument or option
* @param key determines why the processing function was called
* @param outargs the current output argument list
* @return -1 on error, 0 if arg is to be discarded, 1 if arg should be kept
*/
typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key,
struct fuse_args *outargs);
/**
* Option parsing function
*
* If 'args' was returned from a previous call to fuse_opt_parse() or
* it was constructed from
*
* A NULL 'args' is equivalent to an empty argument vector
*
* A NULL 'opts' is equivalent to an 'opts' array containing a single
* end marker
*
* A NULL 'proc' is equivalent to a processing function always
* returning '1'
*
* @param args is the input and output argument list
* @param data is the user data
* @param opts is the option description array
* @param proc is the processing function
* @return -1 on error, 0 on success
*/
int fuse_opt_parse(struct fuse_args *args, void *data,
const struct fuse_opt opts[], fuse_opt_proc_t proc);
/**
* Add an option to a comma separated option list
*
* @param opts is a pointer to an option list, may point to a NULL value
* @param opt is the option to add
* @return -1 on allocation error, 0 on success
*/
int fuse_opt_add_opt(char **opts, const char *opt);
/**
* Add an option, escaping commas, to a comma separated option list
*
* @param opts is a pointer to an option list, may point to a NULL value
* @param opt is the option to add
* @return -1 on allocation error, 0 on success
*/
int fuse_opt_add_opt_escaped(char **opts, const char *opt);
/**
* Add an argument to a NULL terminated argument vector
*
* @param args is the structure containing the current argument list
* @param arg is the new argument to add
* @return -1 on allocation error, 0 on success
*/
int fuse_opt_add_arg(struct fuse_args *args, const char *arg);
/**
* Add an argument at the specified position in a NULL terminated
* argument vector
*
* Adds the argument to the N-th position. This is useful for adding
* options at the beginning of the array which must not come after the
* special '--' option.
*
* @param args is the structure containing the current argument list
* @param pos is the position at which to add the argument
* @param arg is the new argument to add
* @return -1 on allocation error, 0 on success
*/
int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg);
/**
* Free the contents of argument list
*
* The structure itself is not freed
*
* @param args is the structure containing the argument list
*/
void fuse_opt_free_args(struct fuse_args *args);
/**
* Check if an option matches
*
* @param opts is the option description array
* @param opt is the option to match
* @return 1 if a match is found, 0 if not
*/
int fuse_opt_match(const struct fuse_opt opts[], const char *opt);
#ifdef __cplusplus
}
#endif
#endif /* _FUSE_OPT_H_ */
+9
View File
@@ -0,0 +1,9 @@
/*
This header is for compatibility with older software using FUSE.
Please use 'pkg-config --cflags fuse' to set include path. The
correct usage is still '#include <fuse.h>', not '#include
<fuse/fuse.h>'.
*/
#include "fuse/fuse.h"
+24
View File
@@ -0,0 +1,24 @@
/*
libulockmgr: Userspace Lock Manager Library
Copyright (C) 2006 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
#include <stdint.h>
#include <fcntl.h>
#include <sys/types.h>
/**
* Perform POSIX locking operation
*
* @param fd the file descriptor
* @param cmd the locking command (F_GETFL, F_SETLK or F_SETLKW)
* @param lock the lock parameters
* @param owner the lock owner ID cookie
* @param owner_len length of the lock owner ID cookie
* @return 0 on success -errno on error
*/
int ulockmgr_op(int fd, int cmd, struct flock *lock, const void *owner,
size_t owner_len);
+42
View File
@@ -0,0 +1,42 @@
## Process this file with automake to produce Makefile.in
AUTOMAKE_OPTIONS = subdir-objects
AM_CPPFLAGS = -I$(top_srcdir)/include -DFUSERMOUNT_DIR=\"$(bindir)\" \
-D_FILE_OFFSET_BITS=64 -D_REENTRANT -DFUSE_USE_VERSION=26
lib_LTLIBRARIES = libfuse.la libulockmgr.la
if BSD
mount_source = mount_bsd.c
else
mount_source = mount.c mount_util.c mount_util.h
endif
libfuse_la_SOURCES = \
fuse.c \
fuse_i.h \
fuse_kern_chan.c \
fuse_loop.c \
fuse_loop_mt.c \
fuse_lowlevel.c \
fuse_misc.h \
fuse_mt.c \
fuse_opt.c \
fuse_session.c \
fuse_signals.c \
buffer.c \
cuse_lowlevel.c \
helper.c \
$(mount_source)
libfuse_la_LDFLAGS = -pthread @libfuse_libs@ -version-number 2:9:7 \
-Wl,--version-script,$(srcdir)/fuse_versionscript
if NETBSD
libfuse_la_LIBADD = -lperfuse -lpuffs
endif
libulockmgr_la_SOURCES = ulockmgr.c
libulockmgr_la_LDFLAGS = -pthread -version-number 1:0:1
EXTRA_DIST = fuse_versionscript
+318
View File
@@ -0,0 +1,318 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2010 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
#define _GNU_SOURCE
#include "config.h"
#include "fuse_i.h"
#include "fuse_lowlevel.h"
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
size_t fuse_buf_size(const struct fuse_bufvec *bufv)
{
size_t i;
size_t size = 0;
for (i = 0; i < bufv->count; i++) {
if (bufv->buf[i].size == SIZE_MAX)
size = SIZE_MAX;
else
size += bufv->buf[i].size;
}
return size;
}
static size_t min_size(size_t s1, size_t s2)
{
return s1 < s2 ? s1 : s2;
}
static ssize_t fuse_buf_write(const struct fuse_buf *dst, size_t dst_off,
const struct fuse_buf *src, size_t src_off,
size_t len)
{
ssize_t res = 0;
size_t copied = 0;
while (len) {
if (dst->flags & FUSE_BUF_FD_SEEK) {
res = pwrite(dst->fd, src->mem + src_off, len,
dst->pos + dst_off);
} else {
res = write(dst->fd, src->mem + src_off, len);
}
if (res == -1) {
if (!copied)
return -errno;
break;
}
if (res == 0)
break;
copied += res;
if (!(dst->flags & FUSE_BUF_FD_RETRY))
break;
src_off += res;
dst_off += res;
len -= res;
}
return copied;
}
static ssize_t fuse_buf_read(const struct fuse_buf *dst, size_t dst_off,
const struct fuse_buf *src, size_t src_off,
size_t len)
{
ssize_t res = 0;
size_t copied = 0;
while (len) {
if (src->flags & FUSE_BUF_FD_SEEK) {
res = pread(src->fd, dst->mem + dst_off, len,
src->pos + src_off);
} else {
res = read(src->fd, dst->mem + dst_off, len);
}
if (res == -1) {
if (!copied)
return -errno;
break;
}
if (res == 0)
break;
copied += res;
if (!(src->flags & FUSE_BUF_FD_RETRY))
break;
dst_off += res;
src_off += res;
len -= res;
}
return copied;
}
static ssize_t fuse_buf_fd_to_fd(const struct fuse_buf *dst, size_t dst_off,
const struct fuse_buf *src, size_t src_off,
size_t len)
{
char buf[4096];
struct fuse_buf tmp = {
.size = sizeof(buf),
.flags = 0,
};
ssize_t res;
size_t copied = 0;
tmp.mem = buf;
while (len) {
size_t this_len = min_size(tmp.size, len);
size_t read_len;
res = fuse_buf_read(&tmp, 0, src, src_off, this_len);
if (res < 0) {
if (!copied)
return res;
break;
}
if (res == 0)
break;
read_len = res;
res = fuse_buf_write(dst, dst_off, &tmp, 0, read_len);
if (res < 0) {
if (!copied)
return res;
break;
}
if (res == 0)
break;
copied += res;
if (res < this_len)
break;
dst_off += res;
src_off += res;
len -= res;
}
return copied;
}
#ifdef HAVE_SPLICE
static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off,
const struct fuse_buf *src, size_t src_off,
size_t len, enum fuse_buf_copy_flags flags)
{
int splice_flags = 0;
off_t *srcpos = NULL;
off_t *dstpos = NULL;
off_t srcpos_val;
off_t dstpos_val;
ssize_t res;
size_t copied = 0;
if (flags & FUSE_BUF_SPLICE_MOVE)
splice_flags |= SPLICE_F_MOVE;
if (flags & FUSE_BUF_SPLICE_NONBLOCK)
splice_flags |= SPLICE_F_NONBLOCK;
if (src->flags & FUSE_BUF_FD_SEEK) {
srcpos_val = src->pos + src_off;
srcpos = &srcpos_val;
}
if (dst->flags & FUSE_BUF_FD_SEEK) {
dstpos_val = dst->pos + dst_off;
dstpos = &dstpos_val;
}
while (len) {
res = splice(src->fd, srcpos, dst->fd, dstpos, len,
splice_flags);
if (res == -1) {
if (copied)
break;
if (errno != EINVAL || (flags & FUSE_BUF_FORCE_SPLICE))
return -errno;
/* Maybe splice is not supported for this combination */
return fuse_buf_fd_to_fd(dst, dst_off, src, src_off,
len);
}
if (res == 0)
break;
copied += res;
if (!(src->flags & FUSE_BUF_FD_RETRY) &&
!(dst->flags & FUSE_BUF_FD_RETRY)) {
break;
}
len -= res;
}
return copied;
}
#else
static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off,
const struct fuse_buf *src, size_t src_off,
size_t len, enum fuse_buf_copy_flags flags)
{
(void) flags;
return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
}
#endif
static ssize_t fuse_buf_copy_one(const struct fuse_buf *dst, size_t dst_off,
const struct fuse_buf *src, size_t src_off,
size_t len, enum fuse_buf_copy_flags flags)
{
int src_is_fd = src->flags & FUSE_BUF_IS_FD;
int dst_is_fd = dst->flags & FUSE_BUF_IS_FD;
if (!src_is_fd && !dst_is_fd) {
char *dstmem = dst->mem + dst_off;
char *srcmem = src->mem + src_off;
if (dstmem != srcmem) {
if (dstmem + len <= srcmem || srcmem + len <= dstmem)
memcpy(dstmem, srcmem, len);
else
memmove(dstmem, srcmem, len);
}
return len;
} else if (!src_is_fd) {
return fuse_buf_write(dst, dst_off, src, src_off, len);
} else if (!dst_is_fd) {
return fuse_buf_read(dst, dst_off, src, src_off, len);
} else if (flags & FUSE_BUF_NO_SPLICE) {
return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
} else {
return fuse_buf_splice(dst, dst_off, src, src_off, len, flags);
}
}
static const struct fuse_buf *fuse_bufvec_current(struct fuse_bufvec *bufv)
{
if (bufv->idx < bufv->count)
return &bufv->buf[bufv->idx];
else
return NULL;
}
static int fuse_bufvec_advance(struct fuse_bufvec *bufv, size_t len)
{
const struct fuse_buf *buf = fuse_bufvec_current(bufv);
bufv->off += len;
assert(bufv->off <= buf->size);
if (bufv->off == buf->size) {
assert(bufv->idx < bufv->count);
bufv->idx++;
if (bufv->idx == bufv->count)
return 0;
bufv->off = 0;
}
return 1;
}
ssize_t fuse_buf_copy(struct fuse_bufvec *dstv, struct fuse_bufvec *srcv,
enum fuse_buf_copy_flags flags)
{
size_t copied = 0;
if (dstv == srcv)
return fuse_buf_size(dstv);
for (;;) {
const struct fuse_buf *src = fuse_bufvec_current(srcv);
const struct fuse_buf *dst = fuse_bufvec_current(dstv);
size_t src_len;
size_t dst_len;
size_t len;
ssize_t res;
if (src == NULL || dst == NULL)
break;
src_len = src->size - srcv->off;
dst_len = dst->size - dstv->off;
len = min_size(src_len, dst_len);
res = fuse_buf_copy_one(dst, dstv->off, src, srcv->off, len, flags);
if (res < 0) {
if (!copied)
return res;
break;
}
copied += res;
if (!fuse_bufvec_advance(srcv, res) ||
!fuse_bufvec_advance(dstv, res))
break;
if (res < len)
break;
}
return copied;
}
+371
View File
@@ -0,0 +1,371 @@
/*
CUSE: Character device in Userspace
Copyright (C) 2008 SUSE Linux Products GmbH
Copyright (C) 2008 Tejun Heo <teheo@suse.de>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
#include "cuse_lowlevel.h"
#include "fuse_kernel.h"
#include "fuse_i.h"
#include "fuse_opt.h"
#include "fuse_misc.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include <unistd.h>
struct cuse_data {
struct cuse_lowlevel_ops clop;
unsigned max_read;
unsigned dev_major;
unsigned dev_minor;
unsigned flags;
unsigned dev_info_len;
char dev_info[];
};
static struct cuse_lowlevel_ops *req_clop(fuse_req_t req)
{
return &req->f->cuse_data->clop;
}
static void cuse_fll_open(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi)
{
(void)ino;
req_clop(req)->open(req, fi);
}
static void cuse_fll_read(fuse_req_t req, fuse_ino_t ino, size_t size,
off_t off, struct fuse_file_info *fi)
{
(void)ino;
req_clop(req)->read(req, size, off, fi);
}
static void cuse_fll_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
size_t size, off_t off, struct fuse_file_info *fi)
{
(void)ino;
req_clop(req)->write(req, buf, size, off, fi);
}
static void cuse_fll_flush(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi)
{
(void)ino;
req_clop(req)->flush(req, fi);
}
static void cuse_fll_release(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi)
{
(void)ino;
req_clop(req)->release(req, fi);
}
static void cuse_fll_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
struct fuse_file_info *fi)
{
(void)ino;
req_clop(req)->fsync(req, datasync, fi);
}
static void cuse_fll_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg,
struct fuse_file_info *fi, unsigned int flags,
const void *in_buf, size_t in_bufsz, size_t out_bufsz)
{
(void)ino;
req_clop(req)->ioctl(req, cmd, arg, fi, flags, in_buf, in_bufsz,
out_bufsz);
}
static void cuse_fll_poll(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi, struct fuse_pollhandle *ph)
{
(void)ino;
req_clop(req)->poll(req, fi, ph);
}
static size_t cuse_pack_info(int argc, const char **argv, char *buf)
{
size_t size = 0;
int i;
for (i = 0; i < argc; i++) {
size_t len;
len = strlen(argv[i]) + 1;
size += len;
if (buf) {
memcpy(buf, argv[i], len);
buf += len;
}
}
return size;
}
static struct cuse_data *cuse_prep_data(const struct cuse_info *ci,
const struct cuse_lowlevel_ops *clop)
{
struct cuse_data *cd;
size_t dev_info_len;
dev_info_len = cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv,
NULL);
if (dev_info_len > CUSE_INIT_INFO_MAX) {
fprintf(stderr, "cuse: dev_info (%zu) too large, limit=%u\n",
dev_info_len, CUSE_INIT_INFO_MAX);
return NULL;
}
cd = calloc(1, sizeof(*cd) + dev_info_len);
if (!cd) {
fprintf(stderr, "cuse: failed to allocate cuse_data\n");
return NULL;
}
memcpy(&cd->clop, clop, sizeof(cd->clop));
cd->max_read = 131072;
cd->dev_major = ci->dev_major;
cd->dev_minor = ci->dev_minor;
cd->dev_info_len = dev_info_len;
cd->flags = ci->flags;
cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv, cd->dev_info);
return cd;
}
struct fuse_session *cuse_lowlevel_new(struct fuse_args *args,
const struct cuse_info *ci,
const struct cuse_lowlevel_ops *clop,
void *userdata)
{
struct fuse_lowlevel_ops lop;
struct cuse_data *cd;
struct fuse_session *se;
struct fuse_ll *ll;
cd = cuse_prep_data(ci, clop);
if (!cd)
return NULL;
memset(&lop, 0, sizeof(lop));
lop.init = clop->init;
lop.destroy = clop->destroy;
lop.open = clop->open ? cuse_fll_open : NULL;
lop.read = clop->read ? cuse_fll_read : NULL;
lop.write = clop->write ? cuse_fll_write : NULL;
lop.flush = clop->flush ? cuse_fll_flush : NULL;
lop.release = clop->release ? cuse_fll_release : NULL;
lop.fsync = clop->fsync ? cuse_fll_fsync : NULL;
lop.ioctl = clop->ioctl ? cuse_fll_ioctl : NULL;
lop.poll = clop->poll ? cuse_fll_poll : NULL;
se = fuse_lowlevel_new_common(args, &lop, sizeof(lop), userdata);
if (!se) {
free(cd);
return NULL;
}
ll = se->data;
ll->cuse_data = cd;
return se;
}
static int cuse_reply_init(fuse_req_t req, struct cuse_init_out *arg,
char *dev_info, unsigned dev_info_len)
{
struct iovec iov[3];
iov[1].iov_base = arg;
iov[1].iov_len = sizeof(struct cuse_init_out);
iov[2].iov_base = dev_info;
iov[2].iov_len = dev_info_len;
return fuse_send_reply_iov_nofree(req, 0, iov, 3);
}
void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
struct fuse_init_in *arg = (struct fuse_init_in *) inarg;
struct cuse_init_out outarg;
struct fuse_ll *f = req->f;
struct cuse_data *cd = f->cuse_data;
size_t bufsize = fuse_chan_bufsize(req->ch);
struct cuse_lowlevel_ops *clop = req_clop(req);
(void) nodeid;
if (f->debug) {
fprintf(stderr, "CUSE_INIT: %u.%u\n", arg->major, arg->minor);
fprintf(stderr, "flags=0x%08x\n", arg->flags);
}
f->conn.proto_major = arg->major;
f->conn.proto_minor = arg->minor;
f->conn.capable = 0;
f->conn.want = 0;
if (arg->major < 7) {
fprintf(stderr, "cuse: unsupported protocol version: %u.%u\n",
arg->major, arg->minor);
fuse_reply_err(req, EPROTO);
return;
}
if (bufsize < FUSE_MIN_READ_BUFFER) {
fprintf(stderr, "cuse: warning: buffer size too small: %zu\n",
bufsize);
bufsize = FUSE_MIN_READ_BUFFER;
}
bufsize -= 4096;
if (bufsize < f->conn.max_write)
f->conn.max_write = bufsize;
f->got_init = 1;
if (f->op.init)
f->op.init(f->userdata, &f->conn);
memset(&outarg, 0, sizeof(outarg));
outarg.major = FUSE_KERNEL_VERSION;
outarg.minor = FUSE_KERNEL_MINOR_VERSION;
outarg.flags = cd->flags;
outarg.max_read = cd->max_read;
outarg.max_write = f->conn.max_write;
outarg.dev_major = cd->dev_major;
outarg.dev_minor = cd->dev_minor;
if (f->debug) {
fprintf(stderr, " CUSE_INIT: %u.%u\n",
outarg.major, outarg.minor);
fprintf(stderr, " flags=0x%08x\n", outarg.flags);
fprintf(stderr, " max_read=0x%08x\n", outarg.max_read);
fprintf(stderr, " max_write=0x%08x\n", outarg.max_write);
fprintf(stderr, " dev_major=%u\n", outarg.dev_major);
fprintf(stderr, " dev_minor=%u\n", outarg.dev_minor);
fprintf(stderr, " dev_info: %.*s\n", cd->dev_info_len,
cd->dev_info);
}
cuse_reply_init(req, &outarg, cd->dev_info, cd->dev_info_len);
if (clop->init_done)
clop->init_done(f->userdata);
fuse_free_req(req);
}
struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[],
const struct cuse_info *ci,
const struct cuse_lowlevel_ops *clop,
int *multithreaded, void *userdata)
{
const char *devname = "/dev/cuse";
static const struct fuse_opt kill_subtype_opts[] = {
FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_END
};
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
struct fuse_session *se;
struct fuse_chan *ch;
int fd;
int foreground;
int res;
res = fuse_parse_cmdline(&args, NULL, multithreaded, &foreground);
if (res == -1)
goto err_args;
res = fuse_opt_parse(&args, NULL, kill_subtype_opts, NULL);
if (res == -1)
goto err_args;
/*
* Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
* would ensue.
*/
do {
fd = open("/dev/null", O_RDWR);
if (fd > 2)
close(fd);
} while (fd >= 0 && fd <= 2);
se = cuse_lowlevel_new(&args, ci, clop, userdata);
fuse_opt_free_args(&args);
if (se == NULL)
goto err_args;
fd = open(devname, O_RDWR);
if (fd == -1) {
if (errno == ENODEV || errno == ENOENT)
fprintf(stderr, "cuse: device not found, try 'modprobe cuse' first\n");
else
fprintf(stderr, "cuse: failed to open %s: %s\n",
devname, strerror(errno));
goto err_se;
}
ch = fuse_kern_chan_new(fd);
if (!ch) {
close(fd);
goto err_se;
}
fuse_session_add_chan(se, ch);
res = fuse_set_signal_handlers(se);
if (res == -1)
goto err_se;
res = fuse_daemonize(foreground);
if (res == -1)
goto err_sig;
return se;
err_sig:
fuse_remove_signal_handlers(se);
err_se:
fuse_session_destroy(se);
err_args:
fuse_opt_free_args(&args);
return NULL;
}
void cuse_lowlevel_teardown(struct fuse_session *se)
{
fuse_remove_signal_handlers(se);
fuse_session_destroy(se);
}
int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci,
const struct cuse_lowlevel_ops *clop, void *userdata)
{
struct fuse_session *se;
int multithreaded;
int res;
se = cuse_lowlevel_setup(argc, argv, ci, clop, &multithreaded,
userdata);
if (se == NULL)
return 1;
if (multithreaded)
res = fuse_session_loop_mt(se, 0);
else
res = fuse_session_loop(se);
cuse_lowlevel_teardown(se);
if (res == -1)
return 1;
return 0;
}
+4908
View File
File diff suppressed because it is too large Load Diff
+130
View File
@@ -0,0 +1,130 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
#include "fuse.h"
#include "fuse_lowlevel.h"
struct fuse_chan;
struct fuse_ll;
struct fuse_session {
struct fuse_session_ops op;
int (*receive_buf)(struct fuse_session *se, struct fuse_buf *buf,
struct fuse_chan **chp);
void (*process_buf)(void *data, const struct fuse_buf *buf,
struct fuse_chan *ch);
void *data;
volatile int exited;
struct fuse_chan *ch;
};
struct fuse_req {
struct fuse_ll *f;
uint64_t unique;
int ctr;
pthread_mutex_t lock;
struct fuse_ctx ctx;
struct fuse_chan *ch;
int interrupted;
unsigned int ioctl_64bit : 1;
union {
struct {
uint64_t unique;
} i;
struct {
fuse_interrupt_func_t func;
void *data;
} ni;
} u;
struct fuse_req *next;
struct fuse_req *prev;
};
struct fuse_notify_req {
uint64_t unique;
void (*reply)(struct fuse_notify_req *, fuse_req_t, fuse_ino_t,
const void *, const struct fuse_buf *);
struct fuse_notify_req *next;
struct fuse_notify_req *prev;
};
struct fuse_ll {
int debug;
int allow_root;
int atomic_o_trunc;
int no_remote_posix_lock;
int no_remote_flock;
int big_writes;
int splice_write;
int splice_move;
int splice_read;
int no_splice_write;
int no_splice_move;
int no_splice_read;
struct fuse_lowlevel_ops op;
int got_init;
struct cuse_data *cuse_data;
void *userdata;
uid_t owner;
struct fuse_conn_info conn;
struct fuse_req list;
struct fuse_req interrupts;
pthread_mutex_t lock;
int got_destroy;
pthread_key_t pipe_key;
int broken_splice_nonblock;
uint64_t notify_ctr;
struct fuse_notify_req notify_list;
};
struct fuse_cmd {
char *buf;
size_t buflen;
struct fuse_chan *ch;
};
struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
const struct fuse_operations *op,
size_t op_size, void *user_data, int compat);
int fuse_sync_compat_args(struct fuse_args *args);
struct fuse_chan *fuse_kern_chan_new(int fd);
struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args,
const struct fuse_lowlevel_ops *op,
size_t op_size, void *userdata);
void fuse_kern_unmount_compat22(const char *mountpoint);
int fuse_chan_clearfd(struct fuse_chan *ch);
void fuse_kern_unmount(const char *mountpoint, int fd);
int fuse_kern_mount(const char *mountpoint, struct fuse_args *args);
int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
int count);
void fuse_free_req(fuse_req_t req);
struct fuse *fuse_setup_common(int argc, char *argv[],
const struct fuse_operations *op,
size_t op_size,
char **mountpoint,
int *multithreaded,
int *fd,
void *user_data,
int compat);
void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeide, const void *inarg);
int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg);
+103
View File
@@ -0,0 +1,103 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
#include "fuse_lowlevel.h"
#include "fuse_kernel.h"
#include "fuse_i.h"
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <assert.h>
static int fuse_kern_chan_receive(struct fuse_chan **chp, char *buf,
size_t size)
{
struct fuse_chan *ch = *chp;
int err;
ssize_t res;
struct fuse_session *se = fuse_chan_session(ch);
assert(se != NULL);
restart:
res = read(fuse_chan_fd(ch), buf, size);
err = errno;
if (fuse_session_exited(se))
return 0;
if (res == -1) {
/* ENOENT means the operation was interrupted, it's safe
to restart */
if (err == ENOENT)
goto restart;
if (err == ENODEV) {
fuse_session_exit(se);
return 0;
}
/* Errors occurring during normal operation: EINTR (read
interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem
umounted) */
if (err != EINTR && err != EAGAIN)
perror("fuse: reading device");
return -err;
}
if ((size_t) res < sizeof(struct fuse_in_header)) {
fprintf(stderr, "short read on fuse device\n");
return -EIO;
}
return res;
}
static int fuse_kern_chan_send(struct fuse_chan *ch, const struct iovec iov[],
size_t count)
{
if (iov) {
ssize_t res = writev(fuse_chan_fd(ch), iov, count);
int err = errno;
if (res == -1) {
struct fuse_session *se = fuse_chan_session(ch);
assert(se != NULL);
/* ENOENT means the operation was interrupted */
if (!fuse_session_exited(se) && err != ENOENT)
perror("fuse: writing device");
return -err;
}
}
return 0;
}
static void fuse_kern_chan_destroy(struct fuse_chan *ch)
{
int fd = fuse_chan_fd(ch);
if (fd != -1)
close(fd);
}
struct fuse_chan *
fuse_kern_chan_new(int fd_)
{
long pagesize;
size_t bufsize;
struct fuse_chan_ops op =
{
.receive = fuse_kern_chan_receive,
.send = fuse_kern_chan_send,
.destroy = fuse_kern_chan_destroy,
};
pagesize = sysconf(_SC_PAGESIZE);
bufsize = ((FUSE_MAX_MAX_PAGES * pagesize) + 0x1000);
return fuse_chan_new(&op, fd_, bufsize, NULL);
}
+46
View File
@@ -0,0 +1,46 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
#include "fuse_lowlevel.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int fuse_session_loop(struct fuse_session *se)
{
int res = 0;
struct fuse_chan *ch = fuse_session_next_chan(se, NULL);
size_t bufsize = fuse_chan_bufsize(ch);
char *buf = (char *) malloc(bufsize);
if (!buf) {
fprintf(stderr, "fuse: failed to allocate read buffer\n");
return -1;
}
while (!fuse_session_exited(se)) {
struct fuse_chan *tmpch = ch;
struct fuse_buf fbuf = {
.mem = buf,
.size = bufsize,
};
res = fuse_session_receive_buf(se, &fbuf, &tmpch);
if (res == -EINTR)
continue;
if (res <= 0)
break;
fuse_session_process_buf(se, &fbuf, tmpch);
}
free(buf);
fuse_session_reset(se);
return res < 0 ? -1 : 0;
}
+225
View File
@@ -0,0 +1,225 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
#include "fuse_lowlevel.h"
#include "fuse_misc.h"
#include "fuse_kernel.h"
#include "fuse_i.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <semaphore.h>
#include <errno.h>
#include <sys/time.h>
#include <unistd.h>
/* Environment var controlling the thread stack size */
#define ENVNAME_THREAD_STACK "FUSE_THREAD_STACK"
struct fuse_worker {
struct fuse_worker *prev;
struct fuse_worker *next;
pthread_t thread_id;
size_t bufsize;
char *buf;
struct fuse_mt *mt;
};
struct fuse_mt {
struct fuse_session *se;
struct fuse_chan *prevch;
struct fuse_worker main;
sem_t finish;
int exit;
int error;
};
static void list_add_worker(struct fuse_worker *w, struct fuse_worker *next)
{
struct fuse_worker *prev = next->prev;
w->next = next;
w->prev = prev;
prev->next = w;
next->prev = w;
}
static void list_del_worker(struct fuse_worker *w)
{
struct fuse_worker *prev = w->prev;
struct fuse_worker *next = w->next;
prev->next = next;
next->prev = prev;
}
static int fuse_loop_start_thread(struct fuse_mt *mt);
static void *fuse_do_work(void *data)
{
struct fuse_worker *w = (struct fuse_worker *) data;
struct fuse_mt *mt = w->mt;
while (!fuse_session_exited(mt->se)) {
struct fuse_chan *ch = mt->prevch;
struct fuse_buf fbuf = {
.mem = w->buf,
.size = w->bufsize,
};
int res;
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
res = fuse_session_receive_buf(mt->se, &fbuf, &ch);
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
if (res == -EINTR)
continue;
if (res <= 0) {
if (res < 0) {
fuse_session_exit(mt->se);
mt->error = -1;
}
break;
}
if (mt->exit)
return NULL;
fuse_session_process_buf(mt->se, &fbuf, ch);
}
sem_post(&mt->finish);
return NULL;
}
int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg)
{
sigset_t oldset;
sigset_t newset;
int res;
pthread_attr_t attr;
char *stack_size;
/* Override default stack size */
pthread_attr_init(&attr);
stack_size = getenv(ENVNAME_THREAD_STACK);
if (stack_size && pthread_attr_setstacksize(&attr, atoi(stack_size)))
fprintf(stderr, "fuse: invalid stack size: %s\n", stack_size);
/* Disallow signal reception in worker threads */
sigemptyset(&newset);
sigaddset(&newset, SIGTERM);
sigaddset(&newset, SIGINT);
sigaddset(&newset, SIGHUP);
sigaddset(&newset, SIGQUIT);
pthread_sigmask(SIG_BLOCK, &newset, &oldset);
res = pthread_create(thread_id, &attr, func, arg);
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
pthread_attr_destroy(&attr);
if (res != 0) {
fprintf(stderr, "fuse: error creating thread: %s\n",
strerror(res));
return -1;
}
return 0;
}
static int fuse_loop_start_thread(struct fuse_mt *mt)
{
int res;
struct fuse_worker *w = malloc(sizeof(struct fuse_worker));
if (!w) {
fprintf(stderr, "fuse: failed to allocate worker structure\n");
return -1;
}
memset(w, 0, sizeof(struct fuse_worker));
w->bufsize = fuse_chan_bufsize(mt->prevch);
w->buf = malloc(w->bufsize);
w->mt = mt;
if (!w->buf) {
fprintf(stderr, "fuse: failed to allocate read buffer\n");
free(w);
return -1;
}
res = fuse_start_thread(&w->thread_id, fuse_do_work, w);
if (res == -1) {
free(w->buf);
free(w);
return -1;
}
list_add_worker(w, &mt->main);
return 0;
}
static void fuse_join_worker(struct fuse_worker *w)
{
pthread_join(w->thread_id, NULL);
list_del_worker(w);
free(w->buf);
free(w);
}
static int number_of_threads(void)
{
#ifdef _SC_NPROCESSORS_ONLN
return sysconf(_SC_NPROCESSORS_ONLN);
#endif
return 4;
}
int fuse_session_loop_mt(struct fuse_session *se,
const int _threads)
{
int i;
int err;
int threads;
struct fuse_mt mt;
struct fuse_worker *w;
memset(&mt, 0, sizeof(struct fuse_mt));
mt.se = se;
mt.prevch = fuse_session_next_chan(se, NULL);
mt.error = 0;
mt.main.thread_id = pthread_self();
mt.main.prev = mt.main.next = &mt.main;
sem_init(&mt.finish, 0, 0);
threads = ((_threads > 0) ? _threads : number_of_threads());
if(_threads < 0)
threads /= -_threads;
if(threads == 0)
threads = 1;
err = 0;
for(i = 0; (i < threads) && !err; i++)
err = fuse_loop_start_thread(&mt);
if (!err) {
/* sem_wait() is interruptible */
while (!fuse_session_exited(se))
sem_wait(&mt.finish);
for (w = mt.main.next; w != &mt.main; w = w->next)
pthread_cancel(w->thread_id);
mt.exit = 1;
while (mt.main.next != &mt.main)
fuse_join_worker(mt.main.next);
err = mt.error;
}
sem_destroy(&mt.finish);
fuse_session_reset(se);
return err;
}
File diff suppressed because it is too large Load Diff
+57
View File
@@ -0,0 +1,57 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
#include "config.h"
#include <pthread.h>
/*
Versioned symbols cannot be used in some cases because it
- confuse the dynamic linker in uClibc
- not supported on MacOSX (in MachO binary format)
*/
#if (!defined(__UCLIBC__) && !defined(__APPLE__))
#define FUSE_SYMVER(x) __asm__(x)
#else
#define FUSE_SYMVER(x)
#endif
#ifndef USE_UCLIBC
#define fuse_mutex_init(mut) pthread_mutex_init(mut, NULL)
#else
/* Is this hack still needed? */
static inline void fuse_mutex_init(pthread_mutex_t *mut)
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
pthread_mutex_init(mut, &attr);
pthread_mutexattr_destroy(&attr);
}
#endif
#ifdef HAVE_STRUCT_STAT_ST_ATIM
/* Linux */
#define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atim.tv_nsec)
#define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctim.tv_nsec)
#define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtim.tv_nsec)
#define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atim.tv_nsec = (val)
#define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtim.tv_nsec = (val)
#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
/* FreeBSD */
#define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atimespec.tv_nsec)
#define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctimespec.tv_nsec)
#define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtimespec.tv_nsec)
#define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atimespec.tv_nsec = (val)
#define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtimespec.tv_nsec = (val)
#else
#define ST_ATIM_NSEC(stbuf) 0
#define ST_CTIM_NSEC(stbuf) 0
#define ST_MTIM_NSEC(stbuf) 0
#define ST_ATIM_NSEC_SET(stbuf, val) do { } while (0)
#define ST_MTIM_NSEC_SET(stbuf, val) do { } while (0)
#endif
+124
View File
@@ -0,0 +1,124 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
#include "fuse_i.h"
#include "fuse_misc.h"
#include "fuse_lowlevel.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <assert.h>
struct procdata {
struct fuse *f;
struct fuse_chan *prevch;
struct fuse_session *prevse;
fuse_processor_t proc;
void *data;
};
static void mt_session_proc(void *data, const char *buf, size_t len,
struct fuse_chan *ch)
{
struct procdata *pd = (struct procdata *) data;
struct fuse_cmd *cmd = *(struct fuse_cmd **) buf;
(void) len;
(void) ch;
pd->proc(pd->f, cmd, pd->data);
}
static void mt_session_exit(void *data, int val)
{
struct procdata *pd = (struct procdata *) data;
if (val)
fuse_session_exit(pd->prevse);
else
fuse_session_reset(pd->prevse);
}
static int mt_session_exited(void *data)
{
struct procdata *pd = (struct procdata *) data;
return fuse_session_exited(pd->prevse);
}
static int mt_chan_receive(struct fuse_chan **chp, char *buf, size_t size)
{
struct fuse_cmd *cmd;
struct procdata *pd = (struct procdata *) fuse_chan_data(*chp);
assert(size >= sizeof(cmd));
cmd = fuse_read_cmd(pd->f);
if (cmd == NULL)
return 0;
*(struct fuse_cmd **) buf = cmd;
return sizeof(cmd);
}
int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data)
{
int res;
struct procdata pd;
struct fuse_session *prevse = fuse_get_session(f);
struct fuse_session *se;
struct fuse_chan *prevch = fuse_session_next_chan(prevse, NULL);
struct fuse_chan *ch;
struct fuse_session_ops sop = {
.exit = mt_session_exit,
.exited = mt_session_exited,
.process = mt_session_proc,
};
struct fuse_chan_ops cop = {
.receive = mt_chan_receive,
};
pd.f = f;
pd.prevch = prevch;
pd.prevse = prevse;
pd.proc = proc;
pd.data = data;
se = fuse_session_new(&sop, &pd);
if (se == NULL)
return -1;
ch = fuse_chan_new(&cop, fuse_chan_fd(prevch),
sizeof(struct fuse_cmd *), &pd);
if (ch == NULL) {
fuse_session_destroy(se);
return -1;
}
fuse_session_add_chan(se, ch);
res = fuse_session_loop_mt(se,
fuse_config_num_threads(f));
fuse_session_destroy(se);
return res;
}
int fuse_loop_mt(struct fuse *f)
{
if (f == NULL)
return -1;
int res = fuse_start_cleanup_thread(f);
if (res)
return -1;
res = fuse_session_loop_mt(fuse_get_session(f),
fuse_config_num_threads(f));
fuse_stop_cleanup_thread(f);
return res;
}
FUSE_SYMVER(".symver fuse_loop_mt_proc,__fuse_loop_mt@");
+426
View File
@@ -0,0 +1,426 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
#include "fuse_opt.h"
#include "fuse_misc.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
struct fuse_opt_context {
void *data;
const struct fuse_opt *opt;
fuse_opt_proc_t proc;
int argctr;
int argc;
char **argv;
struct fuse_args outargs;
char *opts;
int nonopt;
};
void fuse_opt_free_args(struct fuse_args *args)
{
if (args) {
if (args->argv && args->allocated) {
int i;
for (i = 0; i < args->argc; i++)
free(args->argv[i]);
free(args->argv);
}
args->argc = 0;
args->argv = NULL;
args->allocated = 0;
}
}
static int alloc_failed(void)
{
fprintf(stderr, "fuse: memory allocation failed\n");
return -1;
}
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
{
char **newargv;
char *newarg;
assert(!args->argv || args->allocated);
newarg = strdup(arg);
if (!newarg)
return alloc_failed();
newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *));
if (!newargv) {
free(newarg);
return alloc_failed();
}
args->argv = newargv;
args->allocated = 1;
args->argv[args->argc++] = newarg;
args->argv[args->argc] = NULL;
return 0;
}
static int fuse_opt_insert_arg_common(struct fuse_args *args, int pos,
const char *arg)
{
assert(pos <= args->argc);
if (fuse_opt_add_arg(args, arg) == -1)
return -1;
if (pos != args->argc - 1) {
char *newarg = args->argv[args->argc - 1];
memmove(&args->argv[pos + 1], &args->argv[pos],
sizeof(char *) * (args->argc - pos - 1));
args->argv[pos] = newarg;
}
return 0;
}
int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
{
return fuse_opt_insert_arg_common(args, pos, arg);
}
int fuse_opt_insert_arg_compat(struct fuse_args *args, int pos,
const char *arg);
int fuse_opt_insert_arg_compat(struct fuse_args *args, int pos, const char *arg)
{
return fuse_opt_insert_arg_common(args, pos, arg);
}
static int next_arg(struct fuse_opt_context *ctx, const char *opt)
{
if (ctx->argctr + 1 >= ctx->argc) {
fprintf(stderr, "fuse: missing argument after `%s'\n", opt);
return -1;
}
ctx->argctr++;
return 0;
}
static int add_arg(struct fuse_opt_context *ctx, const char *arg)
{
return fuse_opt_add_arg(&ctx->outargs, arg);
}
static int add_opt_common(char **opts, const char *opt, int esc)
{
unsigned oldlen = *opts ? strlen(*opts) : 0;
char *d = realloc(*opts, oldlen + 1 + strlen(opt) * 2 + 1);
if (!d)
return alloc_failed();
*opts = d;
if (oldlen) {
d += oldlen;
*d++ = ',';
}
for (; *opt; opt++) {
if (esc && (*opt == ',' || *opt == '\\'))
*d++ = '\\';
*d++ = *opt;
}
*d = '\0';
return 0;
}
int fuse_opt_add_opt(char **opts, const char *opt)
{
return add_opt_common(opts, opt, 0);
}
int fuse_opt_add_opt_escaped(char **opts, const char *opt)
{
return add_opt_common(opts, opt, 1);
}
static int add_opt(struct fuse_opt_context *ctx, const char *opt)
{
return add_opt_common(&ctx->opts, opt, 1);
}
static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key,
int iso)
{
if (key == FUSE_OPT_KEY_DISCARD)
return 0;
if (key != FUSE_OPT_KEY_KEEP && ctx->proc) {
int res = ctx->proc(ctx->data, arg, key, &ctx->outargs);
if (res == -1 || !res)
return res;
}
if (iso)
return add_opt(ctx, arg);
else
return add_arg(ctx, arg);
}
static int match_template(const char *t, const char *arg, unsigned *sepp)
{
int arglen = strlen(arg);
const char *sep = strchr(t, '=');
sep = sep ? sep : strchr(t, ' ');
if (sep && (!sep[1] || sep[1] == '%')) {
int tlen = sep - t;
if (sep[0] == '=')
tlen ++;
if (arglen >= tlen && strncmp(arg, t, tlen) == 0) {
*sepp = sep - t;
return 1;
}
}
if (strcmp(t, arg) == 0) {
*sepp = 0;
return 1;
}
return 0;
}
static const struct fuse_opt *find_opt(const struct fuse_opt *opt,
const char *arg, unsigned *sepp)
{
for (; opt && opt->templ; opt++)
if (match_template(opt->templ, arg, sepp))
return opt;
return NULL;
}
int fuse_opt_match(const struct fuse_opt *opts, const char *opt)
{
unsigned dummy;
return find_opt(opts, opt, &dummy) ? 1 : 0;
}
static int process_opt_param(void *var, const char *format, const char *param,
const char *arg)
{
assert(format[0] == '%');
if (format[1] == 's') {
char *copy = strdup(param);
if (!copy)
return alloc_failed();
*(char **) var = copy;
} else {
if (sscanf(param, format, var) != 1) {
fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg);
return -1;
}
}
return 0;
}
static int process_opt(struct fuse_opt_context *ctx,
const struct fuse_opt *opt, unsigned sep,
const char *arg, int iso)
{
if (opt->offset == -1U) {
if (call_proc(ctx, arg, opt->value, iso) == -1)
return -1;
} else {
void *var = ctx->data + opt->offset;
if (sep && opt->templ[sep + 1]) {
const char *param = arg + sep;
if (opt->templ[sep] == '=')
param ++;
if (process_opt_param(var, opt->templ + sep + 1,
param, arg) == -1)
return -1;
} else
*(int *)var = opt->value;
}
return 0;
}
static int process_opt_sep_arg(struct fuse_opt_context *ctx,
const struct fuse_opt *opt, unsigned sep,
const char *arg, int iso)
{
int res;
char *newarg;
char *param;
if (next_arg(ctx, arg) == -1)
return -1;
param = ctx->argv[ctx->argctr];
newarg = malloc(sep + strlen(param) + 1);
if (!newarg)
return alloc_failed();
memcpy(newarg, arg, sep);
strcpy(newarg + sep, param);
res = process_opt(ctx, opt, sep, newarg, iso);
free(newarg);
return res;
}
static int process_gopt(struct fuse_opt_context *ctx, const char *arg, int iso)
{
unsigned sep;
const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep);
if (opt) {
for (; opt; opt = find_opt(opt + 1, arg, &sep)) {
int res;
if (sep && opt->templ[sep] == ' ' && !arg[sep])
res = process_opt_sep_arg(ctx, opt, sep, arg,
iso);
else
res = process_opt(ctx, opt, sep, arg, iso);
if (res == -1)
return -1;
}
return 0;
} else
return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso);
}
static int process_real_option_group(struct fuse_opt_context *ctx, char *opts)
{
char *s = opts;
char *d = s;
int end = 0;
while (!end) {
if (*s == '\0')
end = 1;
if (*s == ',' || end) {
int res;
*d = '\0';
res = process_gopt(ctx, opts, 1);
if (res == -1)
return -1;
d = opts;
} else {
if (s[0] == '\\' && s[1] != '\0') {
s++;
if (s[0] >= '0' && s[0] <= '3' &&
s[1] >= '0' && s[1] <= '7' &&
s[2] >= '0' && s[2] <= '7') {
*d++ = (s[0] - '0') * 0100 +
(s[1] - '0') * 0010 +
(s[2] - '0');
s += 2;
} else {
*d++ = *s;
}
} else {
*d++ = *s;
}
}
s++;
}
return 0;
}
static int process_option_group(struct fuse_opt_context *ctx, const char *opts)
{
int res;
char *copy = strdup(opts);
if (!copy) {
fprintf(stderr, "fuse: memory allocation failed\n");
return -1;
}
res = process_real_option_group(ctx, copy);
free(copy);
return res;
}
static int process_one(struct fuse_opt_context *ctx, const char *arg)
{
if (ctx->nonopt || arg[0] != '-')
return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0);
else if (arg[1] == 'o') {
if (arg[2])
return process_option_group(ctx, arg + 2);
else {
if (next_arg(ctx, arg) == -1)
return -1;
return process_option_group(ctx,
ctx->argv[ctx->argctr]);
}
} else if (arg[1] == '-' && !arg[2]) {
if (add_arg(ctx, arg) == -1)
return -1;
ctx->nonopt = ctx->outargs.argc;
return 0;
} else
return process_gopt(ctx, arg, 0);
}
static int opt_parse(struct fuse_opt_context *ctx)
{
if (ctx->argc) {
if (add_arg(ctx, ctx->argv[0]) == -1)
return -1;
}
for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++)
if (process_one(ctx, ctx->argv[ctx->argctr]) == -1)
return -1;
if (ctx->opts) {
if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 ||
fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1)
return -1;
}
/* If option separator ("--") is the last argument, remove it */
if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc &&
strcmp(ctx->outargs.argv[ctx->outargs.argc - 1], "--") == 0) {
free(ctx->outargs.argv[ctx->outargs.argc - 1]);
ctx->outargs.argv[--ctx->outargs.argc] = NULL;
}
return 0;
}
int fuse_opt_parse(struct fuse_args *args, void *data,
const struct fuse_opt opts[], fuse_opt_proc_t proc)
{
int res;
struct fuse_opt_context ctx = {
.data = data,
.opt = opts,
.proc = proc,
};
if (!args || !args->argv || !args->argc)
return 0;
ctx.argc = args->argc;
ctx.argv = args->argv;
res = opt_parse(&ctx);
if (res != -1) {
struct fuse_args tmp = *args;
*args = ctx.outargs;
ctx.outargs = tmp;
}
free(ctx.opts);
fuse_opt_free_args(&ctx.outargs);
return res;
}
/* This symbol version was mistakenly added to the version script */
FUSE_SYMVER(".symver fuse_opt_insert_arg_compat,fuse_opt_insert_arg@FUSE_2.5");
+240
View File
@@ -0,0 +1,240 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
#include "fuse_i.h"
#include "fuse_misc.h"
#include "fuse_common_compat.h"
#include "fuse_lowlevel_compat.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
struct fuse_chan {
struct fuse_chan_ops op;
struct fuse_session *se;
int fd;
size_t bufsize;
void *data;
int compat;
};
struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data)
{
struct fuse_session *se = (struct fuse_session *) malloc(sizeof(*se));
if (se == NULL) {
fprintf(stderr, "fuse: failed to allocate session\n");
return NULL;
}
memset(se, 0, sizeof(*se));
se->op = *op;
se->data = data;
return se;
}
void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch)
{
assert(se->ch == NULL);
assert(ch->se == NULL);
se->ch = ch;
ch->se = se;
}
void fuse_session_remove_chan(struct fuse_chan *ch)
{
struct fuse_session *se = ch->se;
if (se) {
assert(se->ch == ch);
se->ch = NULL;
ch->se = NULL;
}
}
struct fuse_chan *fuse_session_next_chan(struct fuse_session *se,
struct fuse_chan *ch)
{
assert(ch == NULL || ch == se->ch);
if (ch == NULL)
return se->ch;
else
return NULL;
}
void fuse_session_process(struct fuse_session *se, const char *buf, size_t len,
struct fuse_chan *ch)
{
se->op.process(se->data, buf, len, ch);
}
void fuse_session_process_buf(struct fuse_session *se,
const struct fuse_buf *buf, struct fuse_chan *ch)
{
if (se->process_buf) {
se->process_buf(se->data, buf, ch);
} else {
assert(!(buf->flags & FUSE_BUF_IS_FD));
fuse_session_process(se->data, buf->mem, buf->size, ch);
}
}
int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf,
struct fuse_chan **chp)
{
int res;
if (se->receive_buf) {
res = se->receive_buf(se, buf, chp);
} else {
res = fuse_chan_recv(chp, buf->mem, buf->size);
if (res > 0)
buf->size = res;
}
return res;
}
void fuse_session_destroy(struct fuse_session *se)
{
if (se->op.destroy)
se->op.destroy(se->data);
if (se->ch != NULL)
fuse_chan_destroy(se->ch);
free(se);
}
void fuse_session_exit(struct fuse_session *se)
{
if (se->op.exit)
se->op.exit(se->data, 1);
se->exited = 1;
}
void fuse_session_reset(struct fuse_session *se)
{
if (se->op.exit)
se->op.exit(se->data, 0);
se->exited = 0;
}
int fuse_session_exited(struct fuse_session *se)
{
if (se->op.exited)
return se->op.exited(se->data);
else
return se->exited;
}
void *fuse_session_data(struct fuse_session *se)
{
return se->data;
}
static struct fuse_chan *fuse_chan_new_common(struct fuse_chan_ops *op, int fd,
size_t bufsize, void *data,
int compat)
{
struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch));
if (ch == NULL) {
fprintf(stderr, "fuse: failed to allocate channel\n");
return NULL;
}
memset(ch, 0, sizeof(*ch));
ch->op = *op;
ch->fd = fd;
ch->bufsize = bufsize;
ch->data = data;
ch->compat = compat;
return ch;
}
struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd,
size_t bufsize, void *data)
{
return fuse_chan_new_common(op, fd, bufsize, data, 0);
}
struct fuse_chan *fuse_chan_new_compat24(struct fuse_chan_ops_compat24 *op,
int fd, size_t bufsize, void *data)
{
return fuse_chan_new_common((struct fuse_chan_ops *) op, fd, bufsize,
data, 24);
}
int fuse_chan_fd(struct fuse_chan *ch)
{
return ch->fd;
}
int fuse_chan_clearfd(struct fuse_chan *ch)
{
int fd = ch->fd;
ch->fd = -1;
return fd;
}
size_t fuse_chan_bufsize(struct fuse_chan *ch)
{
return ch->bufsize;
}
void *fuse_chan_data(struct fuse_chan *ch)
{
return ch->data;
}
struct fuse_session *fuse_chan_session(struct fuse_chan *ch)
{
return ch->se;
}
int fuse_chan_recv(struct fuse_chan **chp, char *buf, size_t size)
{
struct fuse_chan *ch = *chp;
if (ch->compat)
return ((struct fuse_chan_ops_compat24 *) &ch->op)
->receive(ch, buf, size);
else
return ch->op.receive(chp, buf, size);
}
int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size)
{
int res;
res = fuse_chan_recv(&ch, buf, size);
return res >= 0 ? res : (res != -EINTR && res != -EAGAIN) ? -1 : 0;
}
int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], size_t count)
{
return ch->op.send(ch, iov, count);
}
void fuse_chan_destroy(struct fuse_chan *ch)
{
fuse_session_remove_chan(ch);
if (ch->op.destroy)
ch->op.destroy(ch);
free(ch);
}
#ifndef __FreeBSD__
FUSE_SYMVER(".symver fuse_chan_new_compat24,fuse_chan_new@FUSE_2.4");
#endif
+72
View File
@@ -0,0 +1,72 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
#include "fuse_lowlevel.h"
#include <stdio.h>
#include <string.h>
#include <signal.h>
static struct fuse_session *fuse_instance;
static void exit_handler(int sig)
{
(void) sig;
if (fuse_instance)
fuse_session_exit(fuse_instance);
}
static int set_one_signal_handler(int sig, void (*handler)(int), int remove)
{
struct sigaction sa;
struct sigaction old_sa;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = remove ? SIG_DFL : handler;
sigemptyset(&(sa.sa_mask));
sa.sa_flags = 0;
if (sigaction(sig, NULL, &old_sa) == -1) {
perror("fuse: cannot get old signal handler");
return -1;
}
if (old_sa.sa_handler == (remove ? handler : SIG_DFL) &&
sigaction(sig, &sa, NULL) == -1) {
perror("fuse: cannot set signal handler");
return -1;
}
return 0;
}
int fuse_set_signal_handlers(struct fuse_session *se)
{
if (set_one_signal_handler(SIGHUP, exit_handler, 0) == -1 ||
set_one_signal_handler(SIGINT, exit_handler, 0) == -1 ||
set_one_signal_handler(SIGTERM, exit_handler, 0) == -1 ||
set_one_signal_handler(SIGPIPE, SIG_IGN, 0) == -1)
return -1;
fuse_instance = se;
return 0;
}
void fuse_remove_signal_handlers(struct fuse_session *se)
{
if (fuse_instance != se)
fprintf(stderr,
"fuse: fuse_remove_signal_handlers: unknown session\n");
else
fuse_instance = NULL;
set_one_signal_handler(SIGHUP, exit_handler, 1);
set_one_signal_handler(SIGINT, exit_handler, 1);
set_one_signal_handler(SIGTERM, exit_handler, 1);
set_one_signal_handler(SIGPIPE, SIG_IGN, 1);
}
+207
View File
@@ -0,0 +1,207 @@
FUSE_2.2 {
global:
fuse_destroy;
fuse_exit;
fuse_exited;
fuse_invalidate;
fuse_is_lib_option;
fuse_loop;
fuse_loop_mt;
fuse_loop_mt_proc;
fuse_main;
fuse_main_compat1;
fuse_main_compat2;
fuse_mount_compat1;
fuse_new_compat1;
fuse_new_compat2;
fuse_process_cmd;
fuse_read_cmd;
fuse_set_getcontext_func;
fuse_setup_compat2;
};
FUSE_2.4 {
global:
fuse_add_dirent;
fuse_chan_bufsize;
fuse_chan_data;
fuse_chan_destroy;
fuse_chan_fd;
fuse_chan_receive;
fuse_chan_send;
fuse_chan_session;
fuse_dirent_size;
fuse_kern_chan_new;
fuse_lowlevel_is_lib_option;
fuse_reply_attr;
fuse_reply_buf;
fuse_reply_entry;
fuse_reply_err;
fuse_reply_none;
fuse_reply_readlink;
fuse_reply_write;
fuse_reply_xattr;
fuse_req_userdata;
fuse_session_add_chan;
fuse_session_destroy;
fuse_session_exit;
fuse_session_exited;
fuse_session_loop;
fuse_session_loop_mt;
fuse_session_new;
fuse_session_next_chan;
fuse_session_process;
fuse_session_reset;
} FUSE_2.2;
FUSE_2.5 {
global:
fuse_lowlevel_new_compat;
fuse_main_real_compat22;
fuse_mount_compat22;
fuse_new_compat22;
fuse_opt_parse;
fuse_opt_add_opt;
fuse_opt_add_arg;
fuse_opt_free_args;
fuse_opt_match;
fuse_parse_cmdline;
fuse_remove_signal_handlers;
fuse_reply_create;
fuse_reply_open;
fuse_reply_open_compat;
fuse_reply_statfs;
fuse_reply_statfs_compat;
fuse_setup_compat22;
fuse_set_signal_handlers;
} FUSE_2.4;
FUSE_2.6 {
global:
fuse_add_direntry;
fuse_chan_new;
fuse_chan_new_compat24;
fuse_chan_recv;
fuse_daemonize;
fuse_get_session;
fuse_interrupted;
fuse_lowlevel_new;
fuse_lowlevel_new_compat25;
fuse_main_real;
fuse_main_real_compat25;
fuse_mount;
fuse_mount_compat25;
fuse_new;
fuse_new_compat25;
fuse_opt_insert_arg;
fuse_reply_lock;
fuse_req_interrupt_func;
fuse_req_interrupted;
fuse_session_remove_chan;
fuse_setup;
fuse_setup_compat25;
fuse_teardown;
fuse_teardown_compat22;
fuse_unmount;
fuse_unmount_compat22;
} FUSE_2.5;
FUSE_2.7 {
global:
fuse_fs_access;
fuse_fs_bmap;
fuse_fs_chmod;
fuse_fs_chown;
fuse_fs_create;
fuse_fs_destroy;
fuse_fs_fgetattr;
fuse_fs_flush;
fuse_fs_fsync;
fuse_fs_fsyncdir;
fuse_fs_ftruncate;
fuse_fs_getattr;
fuse_fs_getxattr;
fuse_fs_init;
fuse_fs_link;
fuse_fs_listxattr;
fuse_fs_lock;
fuse_fs_mkdir;
fuse_fs_mknod;
fuse_fs_new;
fuse_fs_open;
fuse_fs_opendir;
fuse_fs_read;
fuse_fs_readdir;
fuse_fs_readlink;
fuse_fs_release;
fuse_fs_releasedir;
fuse_fs_removexattr;
fuse_fs_rename;
fuse_fs_rmdir;
fuse_fs_setxattr;
fuse_fs_statfs;
fuse_fs_symlink;
fuse_fs_truncate;
fuse_fs_unlink;
fuse_fs_utimens;
fuse_fs_write;
fuse_register_module;
fuse_reply_iov;
fuse_version;
} FUSE_2.6;
FUSE_2.7.5 {
global:
fuse_reply_bmap;
} FUSE_2.7;
FUSE_2.8 {
global:
cuse_lowlevel_new;
cuse_lowlevel_main;
cuse_lowlevel_setup;
cuse_lowlevel_teardown;
fuse_fs_ioctl;
fuse_fs_poll;
fuse_get_context;
fuse_getgroups;
fuse_lowlevel_notify_inval_entry;
fuse_lowlevel_notify_inval_inode;
fuse_lowlevel_notify_poll;
fuse_notify_poll;
fuse_opt_add_opt_escaped;
fuse_pollhandle_destroy;
fuse_reply_ioctl;
fuse_reply_ioctl_iov;
fuse_reply_ioctl_retry;
fuse_reply_poll;
fuse_req_ctx;
fuse_req_getgroups;
fuse_session_data;
} FUSE_2.7.5;
FUSE_2.9 {
global:
fuse_buf_copy;
fuse_buf_size;
fuse_fs_read_buf;
fuse_fs_write_buf;
fuse_lowlevel_notify_retrieve;
fuse_lowlevel_notify_store;
fuse_reply_data;
fuse_session_process_buf;
fuse_session_receive_buf;
fuse_start_cleanup_thread;
fuse_stop_cleanup_thread;
fuse_clean_cache;
fuse_lowlevel_notify_delete;
fuse_fs_flock;
} FUSE_2.8;
FUSE_2.9.1 {
global:
fuse_fs_fallocate;
local:
*;
} FUSE_2.9;
+511
View File
@@ -0,0 +1,511 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
#include "config.h"
#include "fuse_i.h"
#include "fuse_misc.h"
#include "fuse_opt.h"
#include "fuse_lowlevel.h"
#include "fuse_common_compat.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include <sys/param.h>
enum {
KEY_HELP,
KEY_HELP_NOHEADER,
KEY_VERSION,
};
struct helper_opts
{
int singlethread;
int foreground;
int nodefault_subtype;
char *mountpoint;
};
#define FUSE_HELPER_OPT(t, p) { t, offsetof(struct helper_opts, p), 1 }
static
const
struct fuse_opt fuse_helper_opts[] =
{
FUSE_HELPER_OPT("-d", foreground),
FUSE_HELPER_OPT("debug", foreground),
FUSE_HELPER_OPT("-f", foreground),
FUSE_HELPER_OPT("-s", singlethread),
FUSE_HELPER_OPT("fsname=", nodefault_subtype),
FUSE_HELPER_OPT("subtype=", nodefault_subtype),
FUSE_OPT_KEY("-h", KEY_HELP),
FUSE_OPT_KEY("--help", KEY_HELP),
FUSE_OPT_KEY("-ho", KEY_HELP_NOHEADER),
FUSE_OPT_KEY("-V", KEY_VERSION),
FUSE_OPT_KEY("--version", KEY_VERSION),
FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP),
FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP),
FUSE_OPT_END
};
static void usage(const char *progname)
{
fprintf(stderr,
"usage: %s mountpoint [options]\n\n", progname);
fprintf(stderr,
"general options:\n"
" -o opt,[opt...] mount options\n"
" -h --help print help\n"
" -V --version print version\n"
"\n");
}
static void helper_help(void)
{
fprintf(stderr,
"FUSE options:\n"
" -d -o debug enable debug output (implies -f)\n"
" -f foreground operation\n"
" -s disable multi-threaded operation\n"
"\n"
);
}
static void helper_version(void)
{
fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION);
}
static int fuse_helper_opt_proc(void *data, const char *arg, int key,
struct fuse_args *outargs)
{
struct helper_opts *hopts = data;
switch (key) {
case KEY_HELP:
usage(outargs->argv[0]);
/* fall through */
case KEY_HELP_NOHEADER:
helper_help();
return fuse_opt_add_arg(outargs, "-h");
case KEY_VERSION:
helper_version();
return 1;
case FUSE_OPT_KEY_NONOPT:
if (!hopts->mountpoint) {
char mountpoint[PATH_MAX];
if (realpath(arg, mountpoint) == NULL) {
fprintf(stderr,
"fuse: bad mount point `%s': %s\n",
arg, strerror(errno));
return -1;
}
return fuse_opt_add_opt(&hopts->mountpoint, mountpoint);
} else {
fprintf(stderr, "fuse: invalid argument `%s'\n", arg);
return -1;
}
default:
return 1;
}
}
static int add_default_subtype(const char *progname, struct fuse_args *args)
{
int res;
char *subtype_opt;
const char *basename = strrchr(progname, '/');
if (basename == NULL)
basename = progname;
else if (basename[1] != '\0')
basename++;
subtype_opt = (char *) malloc(strlen(basename) + 64);
if (subtype_opt == NULL) {
fprintf(stderr, "fuse: memory allocation failed\n");
return -1;
}
sprintf(subtype_opt, "-osubtype=%s", basename);
res = fuse_opt_add_arg(args, subtype_opt);
free(subtype_opt);
return res;
}
int
fuse_parse_cmdline(struct fuse_args *args_,
char **mountpoint_,
int *multithreaded_,
int *foreground_)
{
int res;
struct helper_opts hopts;
memset(&hopts, 0, sizeof(hopts));
res = fuse_opt_parse(args_,
&hopts,
fuse_helper_opts,
fuse_helper_opt_proc);
if(res == -1)
return -1;
if(!hopts.nodefault_subtype)
{
res = add_default_subtype(args_->argv[0], args_);
if(res == -1)
goto err;
}
if(mountpoint_)
*mountpoint_ = hopts.mountpoint;
else
free(hopts.mountpoint);
if(multithreaded_)
*multithreaded_ = !hopts.singlethread;
if(foreground_)
*foreground_ = hopts.foreground;
return 0;
err:
free(hopts.mountpoint);
return -1;
}
int fuse_daemonize(int foreground)
{
if (!foreground) {
int nullfd;
int waiter[2];
char completed;
if (pipe(waiter)) {
perror("fuse_daemonize: pipe");
return -1;
}
/*
* demonize current process by forking it and killing the
* parent. This makes current process as a child of 'init'.
*/
switch(fork()) {
case -1:
perror("fuse_daemonize: fork");
return -1;
case 0:
break;
default:
read(waiter[0], &completed, sizeof(completed));
_exit(0);
}
if (setsid() == -1) {
perror("fuse_daemonize: setsid");
return -1;
}
(void) chdir("/");
nullfd = open("/dev/null", O_RDWR, 0);
if (nullfd != -1) {
(void) dup2(nullfd, 0);
(void) dup2(nullfd, 1);
(void) dup2(nullfd, 2);
if (nullfd > 2)
close(nullfd);
}
/* Propagate completion of daemon initializatation */
completed = 1;
write(waiter[1], &completed, sizeof(completed));
close(waiter[0]);
close(waiter[1]);
}
return 0;
}
static
struct fuse_chan *
fuse_mount_common(const char *mountpoint_,
struct fuse_args *args_)
{
struct fuse_chan *ch;
int fd;
/*
* Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
* would ensue.
*/
do
{
fd = open("/dev/null", O_RDWR);
if(fd > 2)
close(fd);
} while(fd >= 0 && fd <= 2);
fd = fuse_mount_compat25(mountpoint_, args_);
if(fd == -1)
return NULL;
ch = fuse_kern_chan_new(fd);
if(!ch)
fuse_kern_unmount(mountpoint_, fd);
return ch;
}
struct fuse_chan *
fuse_mount(const char *mountpoint_,
struct fuse_args *args_)
{
return fuse_mount_common(mountpoint_,args_);
}
static void fuse_unmount_common(const char *mountpoint, struct fuse_chan *ch)
{
if (mountpoint) {
int fd = ch ? fuse_chan_clearfd(ch) : -1;
fuse_kern_unmount(mountpoint, fd);
if (ch)
fuse_chan_destroy(ch);
}
}
void fuse_unmount(const char *mountpoint, struct fuse_chan *ch)
{
fuse_unmount_common(mountpoint, ch);
}
struct fuse *fuse_setup_common(int argc, char *argv[],
const struct fuse_operations *op,
size_t op_size,
char **mountpoint,
int *multithreaded,
int *fd,
void *user_data,
int compat)
{
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
struct fuse_chan *ch;
struct fuse *fuse;
int foreground;
int res;
res = fuse_parse_cmdline(&args, mountpoint, multithreaded, &foreground);
if (res == -1)
return NULL;
ch = fuse_mount_common(*mountpoint, &args);
if (!ch) {
fuse_opt_free_args(&args);
goto err_free;
}
fuse = fuse_new_common(ch, &args, op, op_size, user_data, compat);
fuse_opt_free_args(&args);
if (fuse == NULL)
goto err_unmount;
res = fuse_daemonize(foreground);
if (res == -1)
goto err_unmount;
res = fuse_set_signal_handlers(fuse_get_session(fuse));
if (res == -1)
goto err_unmount;
if (fd)
*fd = fuse_chan_fd(ch);
return fuse;
err_unmount:
fuse_unmount_common(*mountpoint, ch);
if (fuse)
fuse_destroy(fuse);
err_free:
free(*mountpoint);
return NULL;
}
struct fuse *fuse_setup(int argc, char *argv[],
const struct fuse_operations *op, size_t op_size,
char **mountpoint, int *multithreaded, void *user_data)
{
return fuse_setup_common(argc, argv, op, op_size, mountpoint,
multithreaded, NULL, user_data, 0);
}
static void fuse_teardown_common(struct fuse *fuse, char *mountpoint)
{
struct fuse_session *se = fuse_get_session(fuse);
struct fuse_chan *ch = fuse_session_next_chan(se, NULL);
fuse_remove_signal_handlers(se);
fuse_unmount_common(mountpoint, ch);
fuse_destroy(fuse);
free(mountpoint);
}
void fuse_teardown(struct fuse *fuse, char *mountpoint)
{
fuse_teardown_common(fuse, mountpoint);
}
static int fuse_main_common(int argc, char *argv[],
const struct fuse_operations *op, size_t op_size,
void *user_data, int compat)
{
struct fuse *fuse;
char *mountpoint;
int multithreaded;
int res;
fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint,
&multithreaded, NULL, user_data, compat);
if (fuse == NULL)
return 1;
if (multithreaded)
res = fuse_loop_mt(fuse);
else
res = fuse_loop(fuse);
fuse_teardown_common(fuse, mountpoint);
if (res == -1)
return 1;
return 0;
}
int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
size_t op_size, void *user_data)
{
return fuse_main_common(argc, argv, op, op_size, user_data, 0);
}
#undef fuse_main
int fuse_main(void);
int fuse_main(void)
{
fprintf(stderr, "fuse_main(): This function does not exist\n");
return -1;
}
int fuse_version(void)
{
return FUSE_VERSION;
}
#include "fuse_compat.h"
#if !defined(__FreeBSD__) && !defined(__NetBSD__)
struct fuse *fuse_setup_compat22(int argc, char *argv[],
const struct fuse_operations_compat22 *op,
size_t op_size, char **mountpoint,
int *multithreaded, int *fd)
{
return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
op_size, mountpoint, multithreaded, fd, NULL,
22);
}
struct fuse *fuse_setup_compat2(int argc, char *argv[],
const struct fuse_operations_compat2 *op,
char **mountpoint, int *multithreaded,
int *fd)
{
return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
sizeof(struct fuse_operations_compat2),
mountpoint, multithreaded, fd, NULL, 21);
}
int fuse_main_real_compat22(int argc, char *argv[],
const struct fuse_operations_compat22 *op,
size_t op_size)
{
return fuse_main_common(argc, argv, (struct fuse_operations *) op,
op_size, NULL, 22);
}
void fuse_main_compat1(int argc, char *argv[],
const struct fuse_operations_compat1 *op)
{
fuse_main_common(argc, argv, (struct fuse_operations *) op,
sizeof(struct fuse_operations_compat1), NULL, 11);
}
int fuse_main_compat2(int argc, char *argv[],
const struct fuse_operations_compat2 *op)
{
return fuse_main_common(argc, argv, (struct fuse_operations *) op,
sizeof(struct fuse_operations_compat2), NULL,
21);
}
int fuse_mount_compat1(const char *mountpoint, const char *args[])
{
/* just ignore mount args for now */
(void) args;
return fuse_mount_compat22(mountpoint, NULL);
}
FUSE_SYMVER(".symver fuse_setup_compat2,__fuse_setup@");
FUSE_SYMVER(".symver fuse_setup_compat22,fuse_setup@FUSE_2.2");
FUSE_SYMVER(".symver fuse_teardown,__fuse_teardown@");
FUSE_SYMVER(".symver fuse_main_compat2,fuse_main@");
FUSE_SYMVER(".symver fuse_main_real_compat22,fuse_main_real@FUSE_2.2");
#endif /* __FreeBSD__ || __NetBSD__ */
struct fuse *fuse_setup_compat25(int argc, char *argv[],
const struct fuse_operations_compat25 *op,
size_t op_size, char **mountpoint,
int *multithreaded, int *fd)
{
return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
op_size, mountpoint, multithreaded, fd, NULL,
25);
}
int fuse_main_real_compat25(int argc, char *argv[],
const struct fuse_operations_compat25 *op,
size_t op_size)
{
return fuse_main_common(argc, argv, (struct fuse_operations *) op,
op_size, NULL, 25);
}
void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint)
{
(void) fd;
fuse_teardown_common(fuse, mountpoint);
}
int fuse_mount_compat25(const char *mountpoint, struct fuse_args *args)
{
return fuse_kern_mount(mountpoint, args);
}
FUSE_SYMVER(".symver fuse_setup_compat25,fuse_setup@FUSE_2.5");
FUSE_SYMVER(".symver fuse_teardown_compat22,fuse_teardown@FUSE_2.2");
FUSE_SYMVER(".symver fuse_main_real_compat25,fuse_main_real@FUSE_2.5");
FUSE_SYMVER(".symver fuse_mount_compat25,fuse_mount@FUSE_2.5");
+8 -14
View File
@@ -1,5 +1,7 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
ISC License
Copyright (c) 2019, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -14,17 +16,9 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __ACCESS_HPP__
#define __ACCESS_HPP__
namespace mergerfs
{
namespace fuse
{
int
access(const char *fusepath,
int mask);
}
}
#if defined __FreeBSD__ || __NetBSD__ || __OpenBSD__ || __DragonFly__
# include "mount_bsd.c"
#else
# include "mount_generic.c"
# include "mount_util.c"
#endif
+391
View File
@@ -0,0 +1,391 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2005-2008 Csaba Henk <csaba.henk@creo.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
#include "fuse_i.h"
#include "fuse_misc.h"
#include "fuse_opt.h"
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stddef.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <paths.h>
#include <limits.h>
#define FUSERMOUNT_PROG "mount_fusefs"
#define FUSE_DEV_TRUNK "/dev/fuse"
enum {
KEY_ALLOW_ROOT,
KEY_RO,
KEY_HELP,
KEY_VERSION,
KEY_KERN
};
struct mount_opts {
int allow_other;
int allow_root;
int ishelp;
char *kernel_opts;
};
#define FUSE_DUAL_OPT_KEY(templ, key) \
FUSE_OPT_KEY(templ, key), FUSE_OPT_KEY("no" templ, key)
static const struct fuse_opt fuse_mount_opts[] = {
{ "allow_other", offsetof(struct mount_opts, allow_other), 1 },
{ "allow_root", offsetof(struct mount_opts, allow_root), 1 },
FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT),
FUSE_OPT_KEY("-r", KEY_RO),
FUSE_OPT_KEY("-h", KEY_HELP),
FUSE_OPT_KEY("--help", KEY_HELP),
FUSE_OPT_KEY("-V", KEY_VERSION),
FUSE_OPT_KEY("--version", KEY_VERSION),
/* standard FreeBSD mount options */
FUSE_DUAL_OPT_KEY("dev", KEY_KERN),
FUSE_DUAL_OPT_KEY("async", KEY_KERN),
FUSE_DUAL_OPT_KEY("atime", KEY_KERN),
FUSE_DUAL_OPT_KEY("dev", KEY_KERN),
FUSE_DUAL_OPT_KEY("exec", KEY_KERN),
FUSE_DUAL_OPT_KEY("suid", KEY_KERN),
FUSE_DUAL_OPT_KEY("symfollow", KEY_KERN),
FUSE_DUAL_OPT_KEY("rdonly", KEY_KERN),
FUSE_DUAL_OPT_KEY("sync", KEY_KERN),
FUSE_DUAL_OPT_KEY("union", KEY_KERN),
FUSE_DUAL_OPT_KEY("userquota", KEY_KERN),
FUSE_DUAL_OPT_KEY("groupquota", KEY_KERN),
FUSE_DUAL_OPT_KEY("clusterr", KEY_KERN),
FUSE_DUAL_OPT_KEY("clusterw", KEY_KERN),
FUSE_DUAL_OPT_KEY("suiddir", KEY_KERN),
FUSE_DUAL_OPT_KEY("snapshot", KEY_KERN),
FUSE_DUAL_OPT_KEY("multilabel", KEY_KERN),
FUSE_DUAL_OPT_KEY("acls", KEY_KERN),
FUSE_DUAL_OPT_KEY("force", KEY_KERN),
FUSE_DUAL_OPT_KEY("update", KEY_KERN),
FUSE_DUAL_OPT_KEY("ro", KEY_KERN),
FUSE_DUAL_OPT_KEY("rw", KEY_KERN),
FUSE_DUAL_OPT_KEY("auto", KEY_KERN),
/* options supported under both Linux and FBSD */
FUSE_DUAL_OPT_KEY("allow_other", KEY_KERN),
FUSE_DUAL_OPT_KEY("default_permissions",KEY_KERN),
FUSE_OPT_KEY("max_read=", KEY_KERN),
FUSE_OPT_KEY("subtype=", KEY_KERN),
/* FBSD FUSE specific mount options */
FUSE_DUAL_OPT_KEY("private", KEY_KERN),
FUSE_DUAL_OPT_KEY("neglect_shares", KEY_KERN),
FUSE_DUAL_OPT_KEY("push_symlinks_in", KEY_KERN),
FUSE_OPT_KEY("nosync_unmount", KEY_KERN),
/* stock FBSD mountopt parsing routine lets anything be negated... */
/*
* Linux specific mount options, but let just the mount util
* handle them
*/
FUSE_OPT_KEY("fsname=", KEY_KERN),
FUSE_OPT_KEY("nonempty", KEY_KERN),
FUSE_OPT_KEY("large_read", KEY_KERN),
FUSE_OPT_END
};
static void mount_help(void)
{
fprintf(stderr,
" -o allow_root allow access to root\n"
);
system(FUSERMOUNT_PROG " --help");
fputc('\n', stderr);
}
static void mount_version(void)
{
system(FUSERMOUNT_PROG " --version");
}
static int fuse_mount_opt_proc(void *data, const char *arg, int key,
struct fuse_args *outargs)
{
struct mount_opts *mo = data;
switch (key) {
case KEY_ALLOW_ROOT:
if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 ||
fuse_opt_add_arg(outargs, "-oallow_root") == -1)
return -1;
return 0;
case KEY_RO:
arg = "ro";
/* fall through */
case KEY_KERN:
return fuse_opt_add_opt(&mo->kernel_opts, arg);
case KEY_HELP:
mount_help();
mo->ishelp = 1;
break;
case KEY_VERSION:
mount_version();
mo->ishelp = 1;
break;
}
return 1;
}
void fuse_unmount_compat22(const char *mountpoint)
{
char dev[128];
char *ssc, *umount_cmd;
FILE *sf;
int rv;
char seekscript[] =
/* error message is annoying in help output */
"exec 2>/dev/null; "
"/usr/bin/fstat " FUSE_DEV_TRUNK "* | "
"/usr/bin/awk 'BEGIN{ getline; if (! ($3 == \"PID\" && $10 == \"NAME\")) exit 1; }; "
" { if ($3 == %d) print $10; }' | "
"/usr/bin/sort | "
"/usr/bin/uniq | "
"/usr/bin/awk '{ i += 1; if (i > 1){ exit 1; }; printf; }; END{ if (i == 0) exit 1; }'";
(void) mountpoint;
/*
* If we don't know the fd, we have to resort to the scripted
* solution -- iterating over the fd-s is unpractical, as we
* don't know how many of open files we have. (This could be
* looked up in procfs -- however, that's optional on FBSD; or
* read out from the kmem -- however, that's bound to
* privileges (in fact, that's what happens when we call the
* setgid kmem fstat(1) utility).
*/
if (asprintf(&ssc, seekscript, getpid()) == -1)
return;
errno = 0;
sf = popen(ssc, "r");
free(ssc);
if (! sf)
return;
fgets(dev, sizeof(dev), sf);
rv = pclose(sf);
if (rv)
return;
if (asprintf(&umount_cmd, "/sbin/umount %s", dev) == -1)
return;
system(umount_cmd);
free(umount_cmd);
}
static void do_unmount(char *dev, int fd)
{
char device_path[SPECNAMELEN + 12];
const char *argv[4];
const char umount_cmd[] = "/sbin/umount";
pid_t pid;
snprintf(device_path, SPECNAMELEN + 12, _PATH_DEV "%s", dev);
argv[0] = umount_cmd;
argv[1] = "-f";
argv[2] = device_path;
argv[3] = NULL;
pid = fork();
if (pid == -1)
return;
if (pid == 0) {
close(fd);
execvp(umount_cmd, (char **)argv);
exit(1);
}
waitpid(pid, NULL, 0);
}
void fuse_kern_unmount(const char *mountpoint, int fd)
{
char *ep, dev[128];
struct stat sbuf;
(void)mountpoint;
if (fstat(fd, &sbuf) == -1)
goto out;
devname_r(sbuf.st_rdev, S_IFCHR, dev, 128);
if (strncmp(dev, "fuse", 4))
goto out;
strtol(dev + 4, &ep, 10);
if (*ep != '\0')
goto out;
do_unmount(dev, fd);
out:
close(fd);
}
/* Check if kernel is doing init in background */
static int init_backgrounded(void)
{
unsigned ibg, len;
len = sizeof(ibg);
if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg, &len, NULL, 0))
return 0;
return ibg;
}
static int fuse_mount_core(const char *mountpoint, const char *opts)
{
const char *mountprog = FUSERMOUNT_PROG;
int fd;
char *fdnam, *dev;
pid_t pid, cpid;
int status;
fdnam = getenv("FUSE_DEV_FD");
if (fdnam) {
char *ep;
fd = strtol(fdnam, &ep, 10);
if (*ep != '\0') {
fprintf(stderr, "invalid value given in FUSE_DEV_FD\n");
return -1;
}
if (fd < 0)
return -1;
goto mount;
}
dev = getenv("FUSE_DEV_NAME");
if (! dev)
dev = (char *)FUSE_DEV_TRUNK;
if ((fd = open(dev, O_RDWR)) < 0) {
perror("fuse: failed to open fuse device");
return -1;
}
mount:
if (getenv("FUSE_NO_MOUNT") || ! mountpoint)
goto out;
pid = fork();
cpid = pid;
if (pid == -1) {
perror("fuse: fork() failed");
close(fd);
return -1;
}
if (pid == 0) {
if (! init_backgrounded()) {
/*
* If init is not backgrounded, we have to
* call the mount util backgrounded, to avoid
* deadlock.
*/
pid = fork();
if (pid == -1) {
perror("fuse: fork() failed");
close(fd);
exit(1);
}
}
if (pid == 0) {
const char *argv[32];
int a = 0;
if (! fdnam && asprintf(&fdnam, "%d", fd) == -1) {
perror("fuse: failed to assemble mount arguments");
exit(1);
}
argv[a++] = mountprog;
if (opts) {
argv[a++] = "-o";
argv[a++] = opts;
}
argv[a++] = fdnam;
argv[a++] = mountpoint;
argv[a++] = NULL;
execvp(mountprog, (char **) argv);
perror("fuse: failed to exec mount program");
exit(1);
}
exit(0);
}
if (waitpid(cpid, &status, 0) == -1 || WEXITSTATUS(status) != 0) {
perror("fuse: failed to mount file system");
close(fd);
return -1;
}
out:
return fd;
}
int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
{
struct mount_opts mo;
int res = -1;
memset(&mo, 0, sizeof(mo));
/* mount util should not try to spawn the daemon */
setenv("MOUNT_FUSEFS_SAFE", "1", 1);
/* to notify the mount util it's called from lib */
setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1);
if (args &&
fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
return -1;
if (mo.allow_other && mo.allow_root) {
fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");
goto out;
}
if (mo.ishelp)
return 0;
res = fuse_mount_core(mountpoint, mo.kernel_opts);
out:
free(mo.kernel_opts);
return res;
}
FUSE_SYMVER(".symver fuse_unmount_compat22,fuse_unmount@FUSE_2.2");
+644
View File
@@ -0,0 +1,644 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
#include "config.h"
#include "fuse_i.h"
#include "fuse_misc.h"
#include "fuse_opt.h"
#include "fuse_common_compat.h"
#include "mount_util.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stddef.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <sys/mount.h>
#ifdef __NetBSD__
#include <perfuse.h>
#define MS_RDONLY MNT_RDONLY
#define MS_NOSUID MNT_NOSUID
#define MS_NODEV MNT_NODEV
#define MS_NOEXEC MNT_NOEXEC
#define MS_SYNCHRONOUS MNT_SYNCHRONOUS
#define MS_NOATIME MNT_NOATIME
#define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0)
#endif
#define FUSERMOUNT_PROG "fusermount"
#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
#ifndef HAVE_FORK
#define fork() vfork()
#endif
#ifndef MS_DIRSYNC
#define MS_DIRSYNC 128
#endif
enum {
KEY_KERN_FLAG,
KEY_KERN_OPT,
KEY_FUSERMOUNT_OPT,
KEY_SUBTYPE_OPT,
KEY_MTAB_OPT,
KEY_ALLOW_ROOT,
KEY_RO,
KEY_HELP,
KEY_VERSION,
};
struct mount_opts {
int allow_other;
int allow_root;
int ishelp;
int flags;
int nonempty;
int auto_unmount;
int blkdev;
char *fsname;
char *subtype;
char *subtype_opt;
char *mtab_opts;
char *fusermount_opts;
char *kernel_opts;
};
#define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 }
static const struct fuse_opt fuse_mount_opts[] = {
FUSE_MOUNT_OPT("allow_other", allow_other),
FUSE_MOUNT_OPT("allow_root", allow_root),
FUSE_MOUNT_OPT("nonempty", nonempty),
FUSE_MOUNT_OPT("blkdev", blkdev),
FUSE_MOUNT_OPT("auto_unmount", auto_unmount),
FUSE_MOUNT_OPT("fsname=%s", fsname),
FUSE_MOUNT_OPT("subtype=%s", subtype),
FUSE_OPT_KEY("allow_other", KEY_KERN_OPT),
FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT),
FUSE_OPT_KEY("nonempty", KEY_FUSERMOUNT_OPT),
FUSE_OPT_KEY("auto_unmount", KEY_FUSERMOUNT_OPT),
FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT),
FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT),
FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT),
FUSE_OPT_KEY("large_read", KEY_KERN_OPT),
FUSE_OPT_KEY("blksize=", KEY_KERN_OPT),
FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT),
FUSE_OPT_KEY("context=", KEY_KERN_OPT),
FUSE_OPT_KEY("fscontext=", KEY_KERN_OPT),
FUSE_OPT_KEY("defcontext=", KEY_KERN_OPT),
FUSE_OPT_KEY("rootcontext=", KEY_KERN_OPT),
FUSE_OPT_KEY("max_read=", KEY_KERN_OPT),
FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP),
FUSE_OPT_KEY("user=", KEY_MTAB_OPT),
FUSE_OPT_KEY("-r", KEY_RO),
FUSE_OPT_KEY("ro", KEY_KERN_FLAG),
FUSE_OPT_KEY("rw", KEY_KERN_FLAG),
FUSE_OPT_KEY("suid", KEY_KERN_FLAG),
FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG),
FUSE_OPT_KEY("dev", KEY_KERN_FLAG),
FUSE_OPT_KEY("nodev", KEY_KERN_FLAG),
FUSE_OPT_KEY("exec", KEY_KERN_FLAG),
FUSE_OPT_KEY("noexec", KEY_KERN_FLAG),
FUSE_OPT_KEY("async", KEY_KERN_FLAG),
FUSE_OPT_KEY("sync", KEY_KERN_FLAG),
FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG),
FUSE_OPT_KEY("atime", KEY_KERN_FLAG),
FUSE_OPT_KEY("noatime", KEY_KERN_FLAG),
FUSE_OPT_KEY("-h", KEY_HELP),
FUSE_OPT_KEY("--help", KEY_HELP),
FUSE_OPT_KEY("-V", KEY_VERSION),
FUSE_OPT_KEY("--version", KEY_VERSION),
FUSE_OPT_END
};
static void mount_help(void)
{
fprintf(stderr,
" -o allow_other allow access to other users\n"
" -o allow_root allow access to root\n"
" -o auto_unmount auto unmount on process termination\n"
" -o nonempty allow mounts over non-empty file/dir\n"
" -o default_permissions enable permission checking by kernel\n"
" -o fsname=NAME set filesystem name\n"
" -o subtype=NAME set filesystem type\n"
" -o large_read issue large read requests (2.4 only)\n"
" -o max_read=N set maximum size of read requests\n"
"\n");
}
static void exec_fusermount(const char *argv[])
{
execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv);
execvp(FUSERMOUNT_PROG, (char **) argv);
}
static void mount_version(void)
{
int pid = fork();
if (!pid) {
const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL };
exec_fusermount(argv);
_exit(1);
} else if (pid != -1)
waitpid(pid, NULL, 0);
}
struct mount_flags {
const char *opt;
unsigned long flag;
int on;
};
static const struct mount_flags mount_flags[] = {
{"rw", MS_RDONLY, 0},
{"ro", MS_RDONLY, 1},
{"suid", MS_NOSUID, 0},
{"nosuid", MS_NOSUID, 1},
{"dev", MS_NODEV, 0},
{"nodev", MS_NODEV, 1},
{"exec", MS_NOEXEC, 0},
{"noexec", MS_NOEXEC, 1},
{"async", MS_SYNCHRONOUS, 0},
{"sync", MS_SYNCHRONOUS, 1},
{"atime", MS_NOATIME, 0},
{"noatime", MS_NOATIME, 1},
#ifndef __NetBSD__
{"dirsync", MS_DIRSYNC, 1},
#endif
{NULL, 0, 0}
};
static void set_mount_flag(const char *s, int *flags)
{
int i;
for (i = 0; mount_flags[i].opt != NULL; i++) {
const char *opt = mount_flags[i].opt;
if (strcmp(opt, s) == 0) {
if (mount_flags[i].on)
*flags |= mount_flags[i].flag;
else
*flags &= ~mount_flags[i].flag;
return;
}
}
fprintf(stderr, "fuse: internal error, can't find mount flag\n");
abort();
}
static int fuse_mount_opt_proc(void *data, const char *arg, int key,
struct fuse_args *outargs)
{
struct mount_opts *mo = data;
switch (key) {
case KEY_ALLOW_ROOT:
if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 ||
fuse_opt_add_arg(outargs, "-oallow_root") == -1)
return -1;
return 0;
case KEY_RO:
arg = "ro";
/* fall through */
case KEY_KERN_FLAG:
set_mount_flag(arg, &mo->flags);
return 0;
case KEY_KERN_OPT:
return fuse_opt_add_opt(&mo->kernel_opts, arg);
case KEY_FUSERMOUNT_OPT:
return fuse_opt_add_opt_escaped(&mo->fusermount_opts, arg);
case KEY_SUBTYPE_OPT:
return fuse_opt_add_opt(&mo->subtype_opt, arg);
case KEY_MTAB_OPT:
return fuse_opt_add_opt(&mo->mtab_opts, arg);
case KEY_HELP:
mount_help();
mo->ishelp = 1;
break;
case KEY_VERSION:
mount_version();
mo->ishelp = 1;
break;
}
return 1;
}
/* return value:
* >= 0 => fd
* -1 => error
*/
static int receive_fd(int fd)
{
struct msghdr msg;
struct iovec iov;
char buf[1];
int rv;
size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)];
struct cmsghdr *cmsg;
iov.iov_base = buf;
iov.iov_len = 1;
memset(&msg, 0, sizeof(msg));
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
/* old BSD implementations should use msg_accrights instead of
* msg_control; the interface is different. */
msg.msg_control = ccmsg;
msg.msg_controllen = sizeof(ccmsg);
while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
if (rv == -1) {
perror("recvmsg");
return -1;
}
if(!rv) {
/* EOF */
return -1;
}
cmsg = CMSG_FIRSTHDR(&msg);
if (cmsg->cmsg_type != SCM_RIGHTS) {
fprintf(stderr, "got control message of unknown type %d\n",
cmsg->cmsg_type);
return -1;
}
return *(int*)CMSG_DATA(cmsg);
}
void fuse_kern_unmount(const char *mountpoint, int fd)
{
int res;
int pid;
if (!mountpoint)
return;
if (fd != -1) {
struct pollfd pfd;
pfd.fd = fd;
pfd.events = 0;
res = poll(&pfd, 1, 0);
/* Need to close file descriptor, otherwise synchronous umount
would recurse into filesystem, and deadlock.
Caller expects fuse_kern_unmount to close the fd, so close it
anyway. */
close(fd);
/* If file poll returns POLLERR on the device file descriptor,
then the filesystem is already unmounted */
if (res == 1 && (pfd.revents & POLLERR))
return;
}
if (geteuid() == 0) {
fuse_mnt_umount("fuse", mountpoint, mountpoint, 1);
return;
}
res = umount2(mountpoint, 2);
if (res == 0)
return;
pid = fork();
if(pid == -1)
return;
if(pid == 0) {
const char *argv[] = { FUSERMOUNT_PROG, "-u", "-q", "-z",
"--", mountpoint, NULL };
exec_fusermount(argv);
_exit(1);
}
waitpid(pid, NULL, 0);
}
void fuse_unmount_compat22(const char *mountpoint)
{
fuse_kern_unmount(mountpoint, -1);
}
static int fuse_mount_fusermount(const char *mountpoint, struct mount_opts *mo,
const char *opts, int quiet)
{
int fds[2], pid;
int res;
int rv;
if (!mountpoint) {
fprintf(stderr, "fuse: missing mountpoint parameter\n");
return -1;
}
res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
if(res == -1) {
perror("fuse: socketpair() failed");
return -1;
}
pid = fork();
if(pid == -1) {
perror("fuse: fork() failed");
close(fds[0]);
close(fds[1]);
return -1;
}
if(pid == 0) {
char env[10];
const char *argv[32];
int a = 0;
if (quiet) {
int fd = open("/dev/null", O_RDONLY);
if (fd != -1) {
dup2(fd, 1);
dup2(fd, 2);
}
}
argv[a++] = FUSERMOUNT_PROG;
if (opts) {
argv[a++] = "-o";
argv[a++] = opts;
}
argv[a++] = "--";
argv[a++] = mountpoint;
argv[a++] = NULL;
close(fds[1]);
fcntl(fds[0], F_SETFD, 0);
snprintf(env, sizeof(env), "%i", fds[0]);
setenv(FUSE_COMMFD_ENV, env, 1);
exec_fusermount(argv);
perror("fuse: failed to exec fusermount");
_exit(1);
}
close(fds[0]);
rv = receive_fd(fds[1]);
if (!mo->auto_unmount) {
/* with auto_unmount option fusermount will not exit until
this socket is closed */
close(fds[1]);
waitpid(pid, NULL, 0); /* bury zombie */
}
return rv;
}
int fuse_mount_compat22(const char *mountpoint, const char *opts)
{
struct mount_opts mo;
memset(&mo, 0, sizeof(mo));
mo.flags = MS_NOSUID | MS_NODEV;
return fuse_mount_fusermount(mountpoint, &mo, opts, 0);
}
static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
const char *mnt_opts)
{
char tmp[128];
const char *devname = "/dev/fuse";
char *source = NULL;
char *type = NULL;
struct stat stbuf;
int fd;
int res;
if (!mnt) {
fprintf(stderr, "fuse: missing mountpoint parameter\n");
return -1;
}
res = stat(mnt, &stbuf);
if (res == -1) {
fprintf(stderr ,"fuse: failed to access mountpoint %s: %s\n",
mnt, strerror(errno));
return -1;
}
if (!mo->nonempty) {
res = fuse_mnt_check_empty("fuse", mnt, stbuf.st_mode,
stbuf.st_size);
if (res == -1)
return -1;
}
if (mo->auto_unmount) {
/* Tell the caller to fallback to fusermount because
auto-unmount does not work otherwise. */
return -2;
}
fd = open(devname, O_RDWR);
if (fd == -1) {
if (errno == ENODEV || errno == ENOENT)
fprintf(stderr, "fuse: device not found, try 'modprobe fuse' first\n");
else
fprintf(stderr, "fuse: failed to open %s: %s\n",
devname, strerror(errno));
return -1;
}
snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%u,group_id=%u",
fd, stbuf.st_mode & S_IFMT, getuid(), getgid());
res = fuse_opt_add_opt(&mo->kernel_opts, tmp);
if (res == -1)
goto out_close;
source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
(mo->subtype ? strlen(mo->subtype) : 0) +
strlen(devname) + 32);
type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
if (!type || !source) {
fprintf(stderr, "fuse: failed to allocate memory\n");
goto out_close;
}
strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
if (mo->subtype) {
strcat(type, ".");
strcat(type, mo->subtype);
}
strcpy(source,
mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
if (res == -1 && errno == ENODEV && mo->subtype) {
/* Probably missing subtype support */
strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
if (mo->fsname) {
if (!mo->blkdev)
sprintf(source, "%s#%s", mo->subtype,
mo->fsname);
} else {
strcpy(source, type);
}
res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
}
if (res == -1) {
/*
* Maybe kernel doesn't support unprivileged mounts, in this
* case try falling back to fusermount
*/
if (errno == EPERM) {
res = -2;
} else {
int errno_save = errno;
if (mo->blkdev && errno == ENODEV &&
!fuse_mnt_check_fuseblk())
fprintf(stderr,
"fuse: 'fuseblk' support missing\n");
else
fprintf(stderr, "fuse: mount failed: %s\n",
strerror(errno_save));
}
goto out_close;
}
#ifndef __NetBSD__
#ifndef IGNORE_MTAB
if (geteuid() == 0) {
char *newmnt = fuse_mnt_resolve_path("fuse", mnt);
res = -1;
if (!newmnt)
goto out_umount;
res = fuse_mnt_add_mount("fuse", source, newmnt, type,
mnt_opts);
free(newmnt);
if (res == -1)
goto out_umount;
}
#endif /* IGNORE_MTAB */
#endif /* __NetBSD__ */
free(type);
free(source);
return fd;
out_umount:
umount2(mnt, 2); /* lazy umount */
out_close:
free(type);
free(source);
close(fd);
return res;
}
static int get_mnt_flag_opts(char **mnt_optsp, int flags)
{
int i;
if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1)
return -1;
for (i = 0; mount_flags[i].opt != NULL; i++) {
if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1)
return -1;
}
return 0;
}
int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
{
struct mount_opts mo;
int res = -1;
char *mnt_opts = NULL;
memset(&mo, 0, sizeof(mo));
mo.flags = MS_NOSUID | MS_NODEV;
if (args &&
fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
return -1;
if (mo.allow_other && mo.allow_root) {
fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");
goto out;
}
res = 0;
if (mo.ishelp)
goto out;
res = -1;
if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1)
goto out;
if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1)
goto out;
if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1)
goto out;
res = fuse_mount_sys(mountpoint, &mo, mnt_opts);
if (res == -2) {
if (mo.fusermount_opts &&
fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1)
goto out;
if (mo.subtype) {
char *tmp_opts = NULL;
res = -1;
if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 ||
fuse_opt_add_opt(&tmp_opts, mo.subtype_opt) == -1) {
free(tmp_opts);
goto out;
}
res = fuse_mount_fusermount(mountpoint, &mo, tmp_opts, 1);
free(tmp_opts);
if (res == -1)
res = fuse_mount_fusermount(mountpoint, &mo,
mnt_opts, 0);
} else {
res = fuse_mount_fusermount(mountpoint, &mo, mnt_opts, 0);
}
}
out:
free(mnt_opts);
free(mo.fsname);
free(mo.subtype);
free(mo.fusermount_opts);
free(mo.subtype_opt);
free(mo.kernel_opts);
free(mo.mtab_opts);
return res;
}
FUSE_SYMVER(".symver fuse_mount_compat22,fuse_mount@FUSE_2.2");
FUSE_SYMVER(".symver fuse_unmount_compat22,fuse_unmount@FUSE_2.2");
+363
View File
@@ -0,0 +1,363 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
#include "mount_util.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <paths.h>
#ifndef __NetBSD__
#include <mntent.h>
#endif
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <sys/param.h>
#ifdef __NetBSD__
#define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0)
#define mtab_needs_update(mnt) 0
#else
static int mtab_needs_update(const char *mnt)
{
int res;
struct stat stbuf;
/* If mtab is within new mount, don't touch it */
if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 &&
_PATH_MOUNTED[strlen(mnt)] == '/')
return 0;
/*
* Skip mtab update if /etc/mtab:
*
* - doesn't exist,
* - is a symlink,
* - is on a read-only filesystem.
*/
res = lstat(_PATH_MOUNTED, &stbuf);
if (res == -1) {
if (errno == ENOENT)
return 0;
} else {
uid_t ruid;
int err;
if (S_ISLNK(stbuf.st_mode))
return 0;
ruid = getuid();
if (ruid != 0)
setreuid(0, -1);
res = access(_PATH_MOUNTED, W_OK);
err = (res == -1) ? errno : 0;
if (ruid != 0)
setreuid(ruid, -1);
if (err == EROFS)
return 0;
}
return 1;
}
#endif /* __NetBSD__ */
static int add_mount(const char *progname, const char *fsname,
const char *mnt, const char *type, const char *opts)
{
int res;
int status;
sigset_t blockmask;
sigset_t oldmask;
sigemptyset(&blockmask);
sigaddset(&blockmask, SIGCHLD);
res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
if (res == -1) {
fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
return -1;
}
res = fork();
if (res == -1) {
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
goto out_restore;
}
if (res == 0) {
char *env = NULL;
sigprocmask(SIG_SETMASK, &oldmask, NULL);
setuid(geteuid());
execle("/bin/mount", "/bin/mount", "--no-canonicalize", "-i",
"-f", "-t", type, "-o", opts, fsname, mnt, NULL, &env);
fprintf(stderr, "%s: failed to execute /bin/mount: %s\n",
progname, strerror(errno));
exit(1);
}
res = waitpid(res, &status, 0);
if (res == -1)
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
if (status != 0)
res = -1;
out_restore:
sigprocmask(SIG_SETMASK, &oldmask, NULL);
return res;
}
int fuse_mnt_add_mount(const char *progname, const char *fsname,
const char *mnt, const char *type, const char *opts)
{
if (!mtab_needs_update(mnt))
return 0;
return add_mount(progname, fsname, mnt, type, opts);
}
static int exec_umount(const char *progname, const char *rel_mnt, int lazy)
{
int res;
int status;
sigset_t blockmask;
sigset_t oldmask;
sigemptyset(&blockmask);
sigaddset(&blockmask, SIGCHLD);
res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
if (res == -1) {
fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
return -1;
}
res = fork();
if (res == -1) {
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
goto out_restore;
}
if (res == 0) {
char *env = NULL;
sigprocmask(SIG_SETMASK, &oldmask, NULL);
setuid(geteuid());
if (lazy) {
execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
"-l", NULL, &env);
} else {
execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
NULL, &env);
}
fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
progname, strerror(errno));
exit(1);
}
res = waitpid(res, &status, 0);
if (res == -1)
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
if (status != 0) {
res = -1;
}
out_restore:
sigprocmask(SIG_SETMASK, &oldmask, NULL);
return res;
}
int fuse_mnt_umount(const char *progname, const char *abs_mnt,
const char *rel_mnt, int lazy)
{
int res;
if (!mtab_needs_update(abs_mnt)) {
res = umount2(rel_mnt, lazy ? 2 : 0);
if (res == -1)
fprintf(stderr, "%s: failed to unmount %s: %s\n",
progname, abs_mnt, strerror(errno));
return res;
}
return exec_umount(progname, rel_mnt, lazy);
}
static int remove_mount(const char *progname, const char *mnt)
{
int res;
int status;
sigset_t blockmask;
sigset_t oldmask;
sigemptyset(&blockmask);
sigaddset(&blockmask, SIGCHLD);
res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
if (res == -1) {
fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
return -1;
}
res = fork();
if (res == -1) {
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
goto out_restore;
}
if (res == 0) {
char *env = NULL;
sigprocmask(SIG_SETMASK, &oldmask, NULL);
setuid(geteuid());
execle("/bin/umount", "/bin/umount", "--no-canonicalize", "-i",
"--fake", mnt, NULL, &env);
fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
progname, strerror(errno));
exit(1);
}
res = waitpid(res, &status, 0);
if (res == -1)
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
if (status != 0)
res = -1;
out_restore:
sigprocmask(SIG_SETMASK, &oldmask, NULL);
return res;
}
int fuse_mnt_remove_mount(const char *progname, const char *mnt)
{
if (!mtab_needs_update(mnt))
return 0;
return remove_mount(progname, mnt);
}
char *fuse_mnt_resolve_path(const char *progname, const char *orig)
{
char buf[PATH_MAX];
char *copy;
char *dst;
char *end;
char *lastcomp;
const char *toresolv;
if (!orig[0]) {
fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname,
orig);
return NULL;
}
copy = strdup(orig);
if (copy == NULL) {
fprintf(stderr, "%s: failed to allocate memory\n", progname);
return NULL;
}
toresolv = copy;
lastcomp = NULL;
for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
if (end[0] != '/') {
char *tmp;
end[1] = '\0';
tmp = strrchr(copy, '/');
if (tmp == NULL) {
lastcomp = copy;
toresolv = ".";
} else {
lastcomp = tmp + 1;
if (tmp == copy)
toresolv = "/";
}
if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
lastcomp = NULL;
toresolv = copy;
}
else if (tmp)
tmp[0] = '\0';
}
if (realpath(toresolv, buf) == NULL) {
fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
strerror(errno));
free(copy);
return NULL;
}
if (lastcomp == NULL)
dst = strdup(buf);
else {
dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
if (dst) {
unsigned buflen = strlen(buf);
if (buflen && buf[buflen-1] == '/')
sprintf(dst, "%s%s", buf, lastcomp);
else
sprintf(dst, "%s/%s", buf, lastcomp);
}
}
free(copy);
if (dst == NULL)
fprintf(stderr, "%s: failed to allocate memory\n", progname);
return dst;
}
int fuse_mnt_check_empty(const char *progname, const char *mnt,
mode_t rootmode, off_t rootsize)
{
int isempty = 1;
if (S_ISDIR(rootmode)) {
struct dirent *ent;
DIR *dp = opendir(mnt);
if (dp == NULL) {
fprintf(stderr,
"%s: failed to open mountpoint for reading: %s\n",
progname, strerror(errno));
return -1;
}
while ((ent = readdir(dp)) != NULL) {
if (strcmp(ent->d_name, ".") != 0 &&
strcmp(ent->d_name, "..") != 0) {
isempty = 0;
break;
}
}
closedir(dp);
} else if (rootsize)
isempty = 0;
if (!isempty) {
fprintf(stderr, "%s: mountpoint is not empty\n", progname);
fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);
return -1;
}
return 0;
}
int fuse_mnt_check_fuseblk(void)
{
char buf[256];
FILE *f = fopen("/proc/filesystems", "r");
if (!f)
return 1;
while (fgets(buf, sizeof(buf), f))
if (strstr(buf, "fuseblk\n")) {
fclose(f);
return 1;
}
fclose(f);
return 0;
}
+19
View File
@@ -0,0 +1,19 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
#include <sys/types.h>
int fuse_mnt_add_mount(const char *progname, const char *fsname,
const char *mnt, const char *type, const char *opts);
int fuse_mnt_remove_mount(const char *progname, const char *mnt);
int fuse_mnt_umount(const char *progname, const char *abs_mnt,
const char *rel_mnt, int lazy);
char *fuse_mnt_resolve_path(const char *progname, const char *orig);
int fuse_mnt_check_empty(const char *progname, const char *mnt,
mode_t rootmode, off_t rootsize);
int fuse_mnt_check_fuseblk(void);
+444
View File
@@ -0,0 +1,444 @@
/*
libulockmgr: Userspace Lock Manager Library
Copyright (C) 2006 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
/* #define DEBUG 1 */
#include "ulockmgr.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <assert.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/wait.h>
struct message {
unsigned intr : 1;
unsigned nofd : 1;
pthread_t thr;
int cmd;
int fd;
struct flock lock;
int error;
};
struct fd_store {
struct fd_store *next;
int fd;
int inuse;
};
struct owner {
struct owner *next;
struct owner *prev;
struct fd_store *fds;
void *id;
size_t id_len;
int cfd;
};
static pthread_mutex_t ulockmgr_lock;
static int ulockmgr_cfd = -1;
static struct owner owner_list = { .next = &owner_list, .prev = &owner_list };
#define MAX_SEND_FDS 2
static void list_del_owner(struct owner *owner)
{
struct owner *prev = owner->prev;
struct owner *next = owner->next;
prev->next = next;
next->prev = prev;
}
static void list_add_owner(struct owner *owner, struct owner *next)
{
struct owner *prev = next->prev;
owner->next = next;
owner->prev = prev;
prev->next = owner;
next->prev = owner;
}
/*
* There's a bug in the linux kernel (< 2.6.22) recv() implementation
* on AF_UNIX, SOCK_STREAM sockets, that could cause it to return
* zero, even if data was available. Retrying the recv will return
* the data in this case.
*/
static int do_recv(int sock, void *buf, size_t len, int flags)
{
int res = recv(sock, buf, len, flags);
if (res == 0)
res = recv(sock, buf, len, flags);
return res;
}
static int ulockmgr_send_message(int sock, void *buf, size_t buflen,
int *fdp, int numfds)
{
struct msghdr msg;
struct cmsghdr *p_cmsg;
struct iovec vec;
size_t cmsgbuf[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)];
int res;
assert(numfds <= MAX_SEND_FDS);
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
p_cmsg = CMSG_FIRSTHDR(&msg);
p_cmsg->cmsg_level = SOL_SOCKET;
p_cmsg->cmsg_type = SCM_RIGHTS;
p_cmsg->cmsg_len = CMSG_LEN(sizeof(int) * numfds);
memcpy(CMSG_DATA(p_cmsg), fdp, sizeof(int) * numfds);
msg.msg_controllen = p_cmsg->cmsg_len;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &vec;
msg.msg_iovlen = 1;
msg.msg_flags = 0;
vec.iov_base = buf;
vec.iov_len = buflen;
res = sendmsg(sock, &msg, MSG_NOSIGNAL);
if (res == -1) {
perror("libulockmgr: sendmsg");
return -1;
}
if ((size_t) res != buflen) {
fprintf(stderr, "libulockmgr: sendmsg short\n");
return -1;
}
return 0;
}
static int ulockmgr_start_daemon(void)
{
int sv[2];
int res;
char tmp[64];
res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
if (res == -1) {
perror("libulockmgr: socketpair");
return -1;
}
snprintf(tmp, sizeof(tmp), "exec ulockmgr_server %i", sv[0]);
res = system(tmp);
close(sv[0]);
if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) {
close(sv[1]);
return -1;
}
ulockmgr_cfd = sv[1];
return 0;
}
static struct owner *ulockmgr_new_owner(const void *id, size_t id_len)
{
int sv[2];
int res;
char c = 'm';
struct owner *o;
if (ulockmgr_cfd == -1 && ulockmgr_start_daemon() == -1)
return NULL;
o = calloc(1, sizeof(struct owner) + id_len);
if (!o) {
fprintf(stderr, "libulockmgr: failed to allocate memory\n");
return NULL;
}
o->id = o + 1;
o->id_len = id_len;
res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
if (res == -1) {
perror("libulockmgr: socketpair");
goto out_free;
}
res = ulockmgr_send_message(ulockmgr_cfd, &c, sizeof(c), &sv[0], 1);
close(sv[0]);
if (res == -1) {
close(ulockmgr_cfd);
ulockmgr_cfd = -1;
goto out_close;
}
o->cfd = sv[1];
memcpy(o->id, id, id_len);
list_add_owner(o, &owner_list);
return o;
out_close:
close(sv[1]);
out_free:
free(o);
return NULL;
}
static int ulockmgr_send_request(struct message *msg, const void *id,
size_t id_len)
{
int sv[2];
int cfd;
struct owner *o;
struct fd_store *f = NULL;
struct fd_store *newf = NULL;
struct fd_store **fp;
int fd = msg->fd;
int cmd = msg->cmd;
int res;
int unlockall = (cmd == F_SETLK && msg->lock.l_type == F_UNLCK &&
msg->lock.l_start == 0 && msg->lock.l_len == 0);
for (o = owner_list.next; o != &owner_list; o = o->next)
if (o->id_len == id_len && memcmp(o->id, id, id_len) == 0)
break;
if (o == &owner_list)
o = NULL;
if (!o && cmd != F_GETLK && msg->lock.l_type != F_UNLCK)
o = ulockmgr_new_owner(id, id_len);
if (!o) {
if (cmd == F_GETLK) {
res = fcntl(msg->fd, F_GETLK, &msg->lock);
return (res == -1) ? -errno : 0;
} else if (msg->lock.l_type == F_UNLCK)
return 0;
else
return -ENOLCK;
}
if (unlockall)
msg->nofd = 1;
else {
for (fp = &o->fds; *fp; fp = &(*fp)->next) {
f = *fp;
if (f->fd == fd) {
msg->nofd = 1;
break;
}
}
}
if (!msg->nofd) {
newf = f = calloc(1, sizeof(struct fd_store));
if (!f) {
fprintf(stderr, "libulockmgr: failed to allocate memory\n");
return -ENOLCK;
}
}
res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
if (res == -1) {
perror("libulockmgr: socketpair");
free(newf);
return -ENOLCK;
}
cfd = sv[1];
sv[1] = msg->fd;
res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv,
msg->nofd ? 1 : 2);
close(sv[0]);
if (res == -1) {
free(newf);
close(cfd);
return -EIO;
}
if (newf) {
newf->fd = msg->fd;
newf->next = o->fds;
o->fds = newf;
}
if (f)
f->inuse++;
res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL);
if (res == -1) {
perror("libulockmgr: recv");
msg->error = EIO;
} else if (res != sizeof(struct message)) {
fprintf(stderr, "libulockmgr: recv short\n");
msg->error = EIO;
} else if (cmd == F_SETLKW && msg->error == EAGAIN) {
pthread_mutex_unlock(&ulockmgr_lock);
while (1) {
sigset_t old;
sigset_t unblock;
int errno_save;
sigemptyset(&unblock);
sigaddset(&unblock, SIGUSR1);
pthread_sigmask(SIG_UNBLOCK, &unblock, &old);
res = do_recv(cfd, msg, sizeof(struct message),
MSG_WAITALL);
errno_save = errno;
pthread_sigmask(SIG_SETMASK, &old, NULL);
if (res == sizeof(struct message))
break;
else if (res >= 0) {
fprintf(stderr, "libulockmgr: recv short\n");
msg->error = EIO;
break;
} else if (errno_save != EINTR) {
errno = errno_save;
perror("libulockmgr: recv");
msg->error = EIO;
break;
}
msg->intr = 1;
res = send(o->cfd, msg, sizeof(struct message),
MSG_NOSIGNAL);
if (res == -1) {
perror("libulockmgr: send");
msg->error = EIO;
break;
}
if (res != sizeof(struct message)) {
fprintf(stderr, "libulockmgr: send short\n");
msg->error = EIO;
break;
}
}
pthread_mutex_lock(&ulockmgr_lock);
}
if (f)
f->inuse--;
close(cfd);
if (unlockall) {
for (fp = &o->fds; *fp;) {
f = *fp;
if (f->fd == fd && !f->inuse) {
*fp = f->next;
free(f);
} else
fp = &f->next;
}
if (!o->fds) {
list_del_owner(o);
close(o->cfd);
free(o);
}
/* Force OK on unlock-all, since it _will_ succeed once the
owner is deleted */
msg->error = 0;
}
return -msg->error;
}
#ifdef DEBUG
static uint32_t owner_hash(const unsigned char *id, size_t id_len)
{
uint32_t h = 0;
size_t i;
for (i = 0; i < id_len; i++)
h = ((h << 8) | (h >> 24)) ^ id[i];
return h;
}
#endif
static int ulockmgr_canonicalize(int fd, struct flock *lock)
{
off_t offset;
if (lock->l_whence == SEEK_CUR) {
offset = lseek(fd, 0, SEEK_CUR);
if (offset == (off_t) -1)
return -errno;
} else if (lock->l_whence == SEEK_END) {
struct stat stbuf;
int res = fstat(fd, &stbuf);
if (res == -1)
return -errno;
offset = stbuf.st_size;
} else
offset = 0;
lock->l_whence = SEEK_SET;
lock->l_start += offset;
if (lock->l_start < 0)
return -EINVAL;
if (lock->l_len < 0) {
lock->l_start += lock->l_len;
if (lock->l_start < 0)
return -EINVAL;
lock->l_len = -lock->l_len;
}
if (lock->l_len && lock->l_start + lock->l_len - 1 < 0)
return -EINVAL;
return 0;
}
int ulockmgr_op(int fd, int cmd, struct flock *lock, const void *owner,
size_t owner_len)
{
int err;
struct message msg;
sigset_t old;
sigset_t block;
if (cmd != F_GETLK && cmd != F_SETLK && cmd != F_SETLKW)
return -EINVAL;
if (lock->l_type != F_RDLCK && lock->l_type != F_WRLCK &&
lock->l_type != F_UNLCK)
return -EINVAL;
if (lock->l_whence != SEEK_SET && lock->l_whence != SEEK_CUR &&
lock->l_whence != SEEK_END)
return -EINVAL;
#ifdef DEBUG
fprintf(stderr, "libulockmgr: %i %i %i %lli %lli own: 0x%08x\n",
cmd, lock->l_type, lock->l_whence, lock->l_start, lock->l_len,
owner_hash(owner, owner_len));
#endif
/* Unlock should never block anyway */
if (cmd == F_SETLKW && lock->l_type == F_UNLCK)
cmd = F_SETLK;
memset(&msg, 0, sizeof(struct message));
msg.cmd = cmd;
msg.fd = fd;
msg.lock = *lock;
err = ulockmgr_canonicalize(fd, &msg.lock);
if (err)
return err;
sigemptyset(&block);
sigaddset(&block, SIGUSR1);
pthread_sigmask(SIG_BLOCK, &block, &old);
pthread_mutex_lock(&ulockmgr_lock);
err = ulockmgr_send_request(&msg, owner, owner_len);
pthread_mutex_unlock(&ulockmgr_lock);
pthread_sigmask(SIG_SETMASK, &old, NULL);
if (!err && cmd == F_GETLK) {
if (msg.lock.l_type == F_UNLCK)
lock->l_type = F_UNLCK;
else
*lock = msg.lock;
}
return err;
}
+58
View File
@@ -0,0 +1,58 @@
## Process this file with automake to produce Makefile.in
AM_CPPFLAGS = -D_FILE_OFFSET_BITS=64
bin_PROGRAMS = fusermount ulockmgr_server
noinst_PROGRAMS = mount.fuse
# we re-use mount_util.c from the library, but do want to keep ourself
# as stand-alone as possible. in order to make an out-of-source build
# possible, we "generate" the file from its original location by
# copying it over.
fusermount_SOURCES = fusermount.c mount_util.c
fusermount_CPPFLAGS = -I$(top_srcdir)/lib
BUILT_SOURCES = mount_util.c
mount_util.c: $(top_srcdir)/lib/mount_util.c
@cp $(top_srcdir)/lib/mount_util.c .
mount_fuse_SOURCES = mount.fuse.c
ulockmgr_server_SOURCES = ulockmgr_server.c
ulockmgr_server_CPPFLAGS = -D_FILE_OFFSET_BITS=64 -D_REENTRANT
ulockmgr_server_LDFLAGS = -pthread
install-exec-hook:
-chmod u+s $(DESTDIR)$(bindir)/fusermount
@if test ! -e $(DESTDIR)/dev/fuse; then \
$(MKDIR_P) $(DESTDIR)/dev; \
echo "mknod $(DESTDIR)/dev/fuse -m 0666 c 10 229 || true"; \
mknod $(DESTDIR)/dev/fuse -m 0666 c 10 229 || true; \
fi
EXTRA_DIST = udev.rules init_script
MOUNT_FUSE_PATH = @MOUNT_FUSE_PATH@
UDEV_RULES_PATH = @UDEV_RULES_PATH@
INIT_D_PATH = @INIT_D_PATH@
install-exec-local:
$(MKDIR_P) $(DESTDIR)$(MOUNT_FUSE_PATH)
$(INSTALL_PROGRAM) $(builddir)/mount.fuse $(DESTDIR)$(MOUNT_FUSE_PATH)/mount.fuse
$(MKDIR_P) $(DESTDIR)$(INIT_D_PATH)
$(INSTALL_SCRIPT) $(srcdir)/init_script $(DESTDIR)$(INIT_D_PATH)/fuse
@if test -x /usr/sbin/update-rc.d; then \
echo "/usr/sbin/update-rc.d fuse start 34 S . start 41 0 6 . || true"; \
/usr/sbin/update-rc.d fuse start 34 S . start 41 0 6 . || true; \
fi
install-data-local:
$(MKDIR_P) $(DESTDIR)$(UDEV_RULES_PATH)
$(INSTALL_DATA) $(srcdir)/udev.rules $(DESTDIR)$(UDEV_RULES_PATH)/99-fuse.rules
uninstall-local:
rm -f $(DESTDIR)$(MOUNT_FUSE_PATH)/mount.fuse
rm -f $(DESTDIR)$(UDEV_RULES_PATH)/99-fuse.rules
rm -f $(DESTDIR)$(INIT_D_PATH)/fuse
@if test -x /usr/sbin/update-rc.d; then \
echo "/usr/sbin/update-rc.d fuse remove || true"; \
/usr/sbin/update-rc.d fuse remove || true; \
fi
File diff suppressed because it is too large Load Diff
+89
View File
@@ -0,0 +1,89 @@
#! /bin/sh
### BEGIN INIT INFO
# Provides: fuse
# Required-Start:
# Should-Start: udev
# Required-Stop:
# Default-Start: S
# Default-Stop:
# Short-Description: Start and stop fuse.
# Description: Load the fuse module and mount the fuse control
# filesystem.
### END INIT INFO
set -e
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
MOUNTPOINT=/sys/fs/fuse/connections
# Gracefully exit if the package has been removed.
which fusermount &>/dev/null || exit 5
case "$1" in
start|restart|force-reload)
if ! grep -qw fuse /proc/filesystems; then
echo -n "Loading fuse module"
if ! modprobe fuse >/dev/null 2>&1; then
echo " failed!"
exit 1
else
echo "."
fi
else
echo "Fuse filesystem already available."
fi
if grep -qw fusectl /proc/filesystems && \
! grep -qw $MOUNTPOINT /proc/mounts; then
echo -n "Mounting fuse control filesystem"
if ! mount -t fusectl fusectl $MOUNTPOINT >/dev/null 2>&1; then
echo " failed!"
exit 1
else
echo "."
fi
else
echo "Fuse control filesystem already available."
fi
;;
stop)
if ! grep -qw fuse /proc/filesystems; then
echo "Fuse filesystem not loaded."
exit 7
fi
if grep -qw $MOUNTPOINT /proc/mounts; then
echo -n "Unmounting fuse control filesystem"
if ! umount $MOUNTPOINT >/dev/null 2>&1; then
echo " failed!"
else
echo "."
fi
else
echo "Fuse control filesystem not mounted."
fi
if grep -qw "^fuse" /proc/modules; then
echo -n "Unloading fuse module"
if ! rmmod fuse >/dev/null 2>&1; then
echo " failed!"
else
echo "."
fi
else
echo "Fuse module not loaded."
fi
;;
status)
echo -n "Checking fuse filesystem"
if ! grep -qw fuse /proc/filesystems; then
echo " not available."
exit 3
else
echo " ok."
fi
;;
*)
echo "Usage: $0 {start|stop|restart|force-reload|status}"
exit 1
;;
esac
exit 0
+230
View File
@@ -0,0 +1,230 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
static char *progname;
static char *xstrdup(const char *s)
{
char *t = strdup(s);
if (!t) {
fprintf(stderr, "%s: failed to allocate memory\n", progname);
exit(1);
}
return t;
}
static void *xrealloc(void *oldptr, size_t size)
{
void *ptr = realloc(oldptr, size);
if (!ptr) {
fprintf(stderr, "%s: failed to allocate memory\n", progname);
exit(1);
}
return ptr;
}
static void add_arg(char **cmdp, const char *opt)
{
size_t optlen = strlen(opt);
size_t cmdlen = *cmdp ? strlen(*cmdp) : 0;
char *cmd = xrealloc(*cmdp, cmdlen + optlen * 4 + 4);
char *s;
s = cmd + cmdlen;
if (*cmdp)
*s++ = ' ';
*s++ = '\'';
for (; *opt; opt++) {
if (*opt == '\'') {
*s++ = '\'';
*s++ = '\\';
*s++ = '\'';
*s++ = '\'';
} else
*s++ = *opt;
}
*s++ = '\'';
*s = '\0';
*cmdp = cmd;
}
static char *add_option(const char *opt, char *options)
{
int oldlen = options ? strlen(options) : 0;
options = xrealloc(options, oldlen + 1 + strlen(opt) + 1);
if (!oldlen)
strcpy(options, opt);
else {
strcat(options, ",");
strcat(options, opt);
}
return options;
}
int main(int argc, char *argv[])
{
char *type = NULL;
char *source;
const char *mountpoint;
char *basename;
char *options = NULL;
char *command = NULL;
char *setuid = NULL;
int i;
int dev = 1;
int suid = 1;
progname = argv[0];
basename = strrchr(argv[0], '/');
if (basename)
basename++;
else
basename = argv[0];
if (strncmp(basename, "mount.fuse.", 11) == 0)
type = basename + 11;
if (strncmp(basename, "mount.fuseblk.", 14) == 0)
type = basename + 14;
if (type && !type[0])
type = NULL;
if (argc < 3) {
fprintf(stderr,
"usage: %s %s destination [-t type] [-o opt[,opts...]]\n",
progname, type ? "source" : "type#[source]");
exit(1);
}
source = argv[1];
if (!source[0])
source = NULL;
mountpoint = argv[2];
for (i = 3; i < argc; i++) {
if (strcmp(argv[i], "-v") == 0) {
continue;
} else if (strcmp(argv[i], "-t") == 0) {
i++;
if (i == argc) {
fprintf(stderr,
"%s: missing argument to option '-t'\n",
progname);
exit(1);
}
type = argv[i];
if (strncmp(type, "fuse.", 5) == 0)
type += 5;
else if (strncmp(type, "fuseblk.", 8) == 0)
type += 8;
if (!type[0]) {
fprintf(stderr,
"%s: empty type given as argument to option '-t'\n",
progname);
exit(1);
}
} else if (strcmp(argv[i], "-o") == 0) {
char *opts;
char *opt;
i++;
if (i == argc)
break;
opts = xstrdup(argv[i]);
opt = strtok(opts, ",");
while (opt) {
int j;
int ignore = 0;
const char *ignore_opts[] = { "",
"user",
"nouser",
"users",
"auto",
"noauto",
"_netdev",
NULL};
if (strncmp(opt, "setuid=", 7) == 0) {
setuid = xstrdup(opt + 7);
ignore = 1;
}
for (j = 0; ignore_opts[j]; j++)
if (strcmp(opt, ignore_opts[j]) == 0)
ignore = 1;
if (!ignore) {
if (strcmp(opt, "nodev") == 0)
dev = 0;
else if (strcmp(opt, "nosuid") == 0)
suid = 0;
options = add_option(opt, options);
}
opt = strtok(NULL, ",");
}
}
}
if (dev)
options = add_option("dev", options);
if (suid)
options = add_option("suid", options);
if (!type) {
if (source) {
type = xstrdup(source);
source = strchr(type, '#');
if (source)
*source++ = '\0';
if (!type[0]) {
fprintf(stderr, "%s: empty filesystem type\n",
progname);
exit(1);
}
} else {
fprintf(stderr, "%s: empty source\n", progname);
exit(1);
}
}
add_arg(&command, type);
if (source)
add_arg(&command, source);
add_arg(&command, mountpoint);
if (options) {
add_arg(&command, "-o");
add_arg(&command, options);
}
if (setuid && setuid[0]) {
char *sucommand = command;
command = NULL;
add_arg(&command, "su");
add_arg(&command, "-");
add_arg(&command, setuid);
add_arg(&command, "-c");
add_arg(&command, sucommand);
} else if (!getenv("HOME")) {
/* Hack to make filesystems work in the boot environment */
setenv("HOME", "/root", 0);
}
execl("/bin/sh", "/bin/sh", "-c", command, NULL);
fprintf(stderr, "%s: failed to execute /bin/sh: %s\n", progname,
strerror(errno));
return 1;
}
+363
View File
@@ -0,0 +1,363 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
#include "mount_util.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <paths.h>
#ifndef __NetBSD__
#include <mntent.h>
#endif
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <sys/param.h>
#ifdef __NetBSD__
#define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0)
#define mtab_needs_update(mnt) 0
#else
static int mtab_needs_update(const char *mnt)
{
int res;
struct stat stbuf;
/* If mtab is within new mount, don't touch it */
if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 &&
_PATH_MOUNTED[strlen(mnt)] == '/')
return 0;
/*
* Skip mtab update if /etc/mtab:
*
* - doesn't exist,
* - is a symlink,
* - is on a read-only filesystem.
*/
res = lstat(_PATH_MOUNTED, &stbuf);
if (res == -1) {
if (errno == ENOENT)
return 0;
} else {
uid_t ruid;
int err;
if (S_ISLNK(stbuf.st_mode))
return 0;
ruid = getuid();
if (ruid != 0)
setreuid(0, -1);
res = access(_PATH_MOUNTED, W_OK);
err = (res == -1) ? errno : 0;
if (ruid != 0)
setreuid(ruid, -1);
if (err == EROFS)
return 0;
}
return 1;
}
#endif /* __NetBSD__ */
static int add_mount(const char *progname, const char *fsname,
const char *mnt, const char *type, const char *opts)
{
int res;
int status;
sigset_t blockmask;
sigset_t oldmask;
sigemptyset(&blockmask);
sigaddset(&blockmask, SIGCHLD);
res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
if (res == -1) {
fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
return -1;
}
res = fork();
if (res == -1) {
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
goto out_restore;
}
if (res == 0) {
char *env = NULL;
sigprocmask(SIG_SETMASK, &oldmask, NULL);
setuid(geteuid());
execle("/bin/mount", "/bin/mount", "--no-canonicalize", "-i",
"-f", "-t", type, "-o", opts, fsname, mnt, NULL, &env);
fprintf(stderr, "%s: failed to execute /bin/mount: %s\n",
progname, strerror(errno));
exit(1);
}
res = waitpid(res, &status, 0);
if (res == -1)
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
if (status != 0)
res = -1;
out_restore:
sigprocmask(SIG_SETMASK, &oldmask, NULL);
return res;
}
int fuse_mnt_add_mount(const char *progname, const char *fsname,
const char *mnt, const char *type, const char *opts)
{
if (!mtab_needs_update(mnt))
return 0;
return add_mount(progname, fsname, mnt, type, opts);
}
static int exec_umount(const char *progname, const char *rel_mnt, int lazy)
{
int res;
int status;
sigset_t blockmask;
sigset_t oldmask;
sigemptyset(&blockmask);
sigaddset(&blockmask, SIGCHLD);
res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
if (res == -1) {
fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
return -1;
}
res = fork();
if (res == -1) {
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
goto out_restore;
}
if (res == 0) {
char *env = NULL;
sigprocmask(SIG_SETMASK, &oldmask, NULL);
setuid(geteuid());
if (lazy) {
execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
"-l", NULL, &env);
} else {
execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
NULL, &env);
}
fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
progname, strerror(errno));
exit(1);
}
res = waitpid(res, &status, 0);
if (res == -1)
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
if (status != 0) {
res = -1;
}
out_restore:
sigprocmask(SIG_SETMASK, &oldmask, NULL);
return res;
}
int fuse_mnt_umount(const char *progname, const char *abs_mnt,
const char *rel_mnt, int lazy)
{
int res;
if (!mtab_needs_update(abs_mnt)) {
res = umount2(rel_mnt, lazy ? 2 : 0);
if (res == -1)
fprintf(stderr, "%s: failed to unmount %s: %s\n",
progname, abs_mnt, strerror(errno));
return res;
}
return exec_umount(progname, rel_mnt, lazy);
}
static int remove_mount(const char *progname, const char *mnt)
{
int res;
int status;
sigset_t blockmask;
sigset_t oldmask;
sigemptyset(&blockmask);
sigaddset(&blockmask, SIGCHLD);
res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
if (res == -1) {
fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
return -1;
}
res = fork();
if (res == -1) {
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
goto out_restore;
}
if (res == 0) {
char *env = NULL;
sigprocmask(SIG_SETMASK, &oldmask, NULL);
setuid(geteuid());
execle("/bin/umount", "/bin/umount", "--no-canonicalize", "-i",
"--fake", mnt, NULL, &env);
fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
progname, strerror(errno));
exit(1);
}
res = waitpid(res, &status, 0);
if (res == -1)
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
if (status != 0)
res = -1;
out_restore:
sigprocmask(SIG_SETMASK, &oldmask, NULL);
return res;
}
int fuse_mnt_remove_mount(const char *progname, const char *mnt)
{
if (!mtab_needs_update(mnt))
return 0;
return remove_mount(progname, mnt);
}
char *fuse_mnt_resolve_path(const char *progname, const char *orig)
{
char buf[PATH_MAX];
char *copy;
char *dst;
char *end;
char *lastcomp;
const char *toresolv;
if (!orig[0]) {
fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname,
orig);
return NULL;
}
copy = strdup(orig);
if (copy == NULL) {
fprintf(stderr, "%s: failed to allocate memory\n", progname);
return NULL;
}
toresolv = copy;
lastcomp = NULL;
for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
if (end[0] != '/') {
char *tmp;
end[1] = '\0';
tmp = strrchr(copy, '/');
if (tmp == NULL) {
lastcomp = copy;
toresolv = ".";
} else {
lastcomp = tmp + 1;
if (tmp == copy)
toresolv = "/";
}
if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
lastcomp = NULL;
toresolv = copy;
}
else if (tmp)
tmp[0] = '\0';
}
if (realpath(toresolv, buf) == NULL) {
fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
strerror(errno));
free(copy);
return NULL;
}
if (lastcomp == NULL)
dst = strdup(buf);
else {
dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
if (dst) {
unsigned buflen = strlen(buf);
if (buflen && buf[buflen-1] == '/')
sprintf(dst, "%s%s", buf, lastcomp);
else
sprintf(dst, "%s/%s", buf, lastcomp);
}
}
free(copy);
if (dst == NULL)
fprintf(stderr, "%s: failed to allocate memory\n", progname);
return dst;
}
int fuse_mnt_check_empty(const char *progname, const char *mnt,
mode_t rootmode, off_t rootsize)
{
int isempty = 1;
if (S_ISDIR(rootmode)) {
struct dirent *ent;
DIR *dp = opendir(mnt);
if (dp == NULL) {
fprintf(stderr,
"%s: failed to open mountpoint for reading: %s\n",
progname, strerror(errno));
return -1;
}
while ((ent = readdir(dp)) != NULL) {
if (strcmp(ent->d_name, ".") != 0 &&
strcmp(ent->d_name, "..") != 0) {
isempty = 0;
break;
}
}
closedir(dp);
} else if (rootsize)
isempty = 0;
if (!isempty) {
fprintf(stderr, "%s: mountpoint is not empty\n", progname);
fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);
return -1;
}
return 0;
}
int fuse_mnt_check_fuseblk(void)
{
char buf[256];
FILE *f = fopen("/proc/filesystems", "r");
if (!f)
return 1;
while (fgets(buf, sizeof(buf), f))
if (strstr(buf, "fuseblk\n")) {
fclose(f);
return 1;
}
fclose(f);
return 0;
}
+1
View File
@@ -0,0 +1 @@
KERNEL=="fuse", MODE="0666"
+425
View File
@@ -0,0 +1,425 @@
/*
ulockmgr_server: Userspace Lock Manager Server
Copyright (C) 2006 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
/* #define DEBUG 1 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <pthread.h>
#include <stdint.h>
#include <errno.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
struct message {
unsigned intr : 1;
unsigned nofd : 1;
pthread_t thr;
int cmd;
int fd;
struct flock lock;
int error;
};
struct fd_store {
struct fd_store *next;
int fd;
int origfd;
int inuse;
};
struct owner {
struct fd_store *fds;
pthread_mutex_t lock;
};
struct req_data {
struct owner *o;
int cfd;
struct fd_store *f;
struct message msg;
};
#define MAX_SEND_FDS 2
static int receive_message(int sock, void *buf, size_t buflen, int *fdp,
int *numfds)
{
struct msghdr msg;
struct iovec iov;
size_t ccmsg[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)];
struct cmsghdr *cmsg;
int res;
int i;
assert(*numfds <= MAX_SEND_FDS);
iov.iov_base = buf;
iov.iov_len = buflen;
memset(&msg, 0, sizeof(msg));
memset(ccmsg, -1, sizeof(ccmsg));
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = ccmsg;
msg.msg_controllen = sizeof(ccmsg);
res = recvmsg(sock, &msg, MSG_WAITALL);
if (!res) {
/* retry on zero return, see do_recv() in ulockmgr.c */
res = recvmsg(sock, &msg, MSG_WAITALL);
if (!res)
return 0;
}
if (res == -1) {
perror("ulockmgr_server: recvmsg");
return -1;
}
if ((size_t) res != buflen) {
fprintf(stderr, "ulockmgr_server: short message received\n");
return -1;
}
cmsg = CMSG_FIRSTHDR(&msg);
if (cmsg) {
if (cmsg->cmsg_type != SCM_RIGHTS) {
fprintf(stderr,
"ulockmgr_server: unknown control message %d\n",
cmsg->cmsg_type);
return -1;
}
memcpy(fdp, CMSG_DATA(cmsg), sizeof(int) * *numfds);
if (msg.msg_flags & MSG_CTRUNC) {
fprintf(stderr,
"ulockmgr_server: control message truncated\n");
for (i = 0; i < *numfds; i++)
close(fdp[i]);
*numfds = 0;
}
} else {
if (msg.msg_flags & MSG_CTRUNC) {
fprintf(stderr,
"ulockmgr_server: control message truncated(*)\n");
/* There's a bug in the Linux kernel, that if
not all file descriptors were allocated,
then the cmsg header is not filled in */
cmsg = (struct cmsghdr *) ccmsg;
memcpy(fdp, CMSG_DATA(cmsg), sizeof(int) * *numfds);
for (i = 0; i < *numfds; i++)
close(fdp[i]);
}
*numfds = 0;
}
return res;
}
static int closefrom(int minfd)
{
DIR *dir = opendir("/proc/self/fd");
if (dir) {
int dfd = dirfd(dir);
struct dirent *ent;
while ((ent = readdir(dir))) {
char *end;
int fd = strtol(ent->d_name, &end, 10);
if (ent->d_name[0] && !end[0] && fd >= minfd &&
fd != dfd)
close(fd);
}
closedir(dir);
}
return 0;
}
static void send_reply(int cfd, struct message *msg)
{
int res = send(cfd, msg, sizeof(struct message), MSG_NOSIGNAL);
if (res == -1)
perror("ulockmgr_server: sending reply");
#ifdef DEBUG
fprintf(stderr, "ulockmgr_server: error: %i\n", msg->error);
#endif
}
static void *process_request(void *d_)
{
struct req_data *d = d_;
int res;
assert(d->msg.cmd == F_SETLKW);
res = fcntl(d->f->fd, F_SETLK, &d->msg.lock);
if (res == -1 && errno == EAGAIN) {
d->msg.error = EAGAIN;
d->msg.thr = pthread_self();
send_reply(d->cfd, &d->msg);
res = fcntl(d->f->fd, F_SETLKW, &d->msg.lock);
}
d->msg.error = (res == -1) ? errno : 0;
pthread_mutex_lock(&d->o->lock);
d->f->inuse--;
pthread_mutex_unlock(&d->o->lock);
send_reply(d->cfd, &d->msg);
close(d->cfd);
free(d);
return NULL;
}
static void process_message(struct owner *o, struct message *msg, int cfd,
int fd)
{
struct fd_store *f = NULL;
struct fd_store *newf = NULL;
struct fd_store **fp;
struct req_data *d;
pthread_t tid;
int res;
#ifdef DEBUG
fprintf(stderr, "ulockmgr_server: %i %i %i %lli %lli\n",
msg->cmd, msg->lock.l_type, msg->lock.l_whence,
msg->lock.l_start, msg->lock.l_len);
#endif
if (msg->cmd == F_SETLK && msg->lock.l_type == F_UNLCK &&
msg->lock.l_start == 0 && msg->lock.l_len == 0) {
for (fp = &o->fds; *fp;) {
f = *fp;
if (f->origfd == msg->fd && !f->inuse) {
close(f->fd);
*fp = f->next;
free(f);
} else
fp = &f->next;
}
if (!msg->nofd)
close(fd);
msg->error = 0;
send_reply(cfd, msg);
close(cfd);
return;
}
if (msg->nofd) {
for (fp = &o->fds; *fp; fp = &(*fp)->next) {
f = *fp;
if (f->origfd == msg->fd)
break;
}
if (!*fp) {
fprintf(stderr, "ulockmgr_server: fd %i not found\n",
msg->fd);
msg->error = EIO;
send_reply(cfd, msg);
close(cfd);
return;
}
} else {
newf = f = malloc(sizeof(struct fd_store));
if (!f) {
msg->error = ENOLCK;
send_reply(cfd, msg);
close(cfd);
return;
}
f->fd = fd;
f->origfd = msg->fd;
f->inuse = 0;
}
if (msg->cmd == F_GETLK || msg->cmd == F_SETLK ||
msg->lock.l_type == F_UNLCK) {
res = fcntl(f->fd, msg->cmd, &msg->lock);
msg->error = (res == -1) ? errno : 0;
send_reply(cfd, msg);
close(cfd);
if (newf) {
newf->next = o->fds;
o->fds = newf;
}
return;
}
d = malloc(sizeof(struct req_data));
if (!d) {
msg->error = ENOLCK;
send_reply(cfd, msg);
close(cfd);
free(newf);
return;
}
f->inuse++;
d->o = o;
d->cfd = cfd;
d->f = f;
d->msg = *msg;
res = pthread_create(&tid, NULL, process_request, d);
if (res) {
msg->error = ENOLCK;
send_reply(cfd, msg);
close(cfd);
free(d);
f->inuse--;
free(newf);
return;
}
if (newf) {
newf->next = o->fds;
o->fds = newf;
}
pthread_detach(tid);
}
static void sigusr1_handler(int sig)
{
(void) sig;
/* Nothing to do */
}
static void process_owner(int cfd)
{
struct owner o;
struct sigaction sa;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = sigusr1_handler;
sigemptyset(&sa.sa_mask);
if (sigaction(SIGUSR1, &sa, NULL) == -1) {
perror("ulockmgr_server: cannot set sigusr1 signal handler");
exit(1);
}
memset(&o, 0, sizeof(struct owner));
pthread_mutex_init(&o.lock, NULL);
while (1) {
struct message msg;
int rfds[2];
int res;
int numfds = 2;
res = receive_message(cfd, &msg, sizeof(msg), rfds, &numfds);
if (!res)
break;
if (res == -1)
exit(1);
if (msg.intr) {
if (numfds != 0)
fprintf(stderr,
"ulockmgr_server: too many fds for intr\n");
pthread_kill(msg.thr, SIGUSR1);
} else {
if (numfds != 2)
continue;
pthread_mutex_lock(&o.lock);
process_message(&o, &msg, rfds[0], rfds[1]);
pthread_mutex_unlock(&o.lock);
}
}
if (o.fds)
fprintf(stderr,
"ulockmgr_server: open file descriptors on exit\n");
}
int main(int argc, char *argv[])
{
int nullfd;
char *end;
int cfd;
sigset_t empty;
if (argc != 2 || !argv[1][0])
goto out_inval;
cfd = strtol(argv[1], &end, 10);
if (*end)
goto out_inval;
/* demonize current process */
switch(fork()) {
case -1:
perror("ulockmgr_server: fork");
exit(1);
case 0:
break;
default:
_exit(0);
}
if (setsid() == -1) {
perror("ulockmgr_server: setsid");
exit(1);
}
(void) chdir("/");
sigemptyset(&empty);
sigprocmask(SIG_SETMASK, &empty, NULL);
if (dup2(cfd, 4) == -1) {
perror("ulockmgr_server: dup2");
exit(1);
}
cfd = 4;
nullfd = open("/dev/null", O_RDWR);
if (nullfd >= 0) {
dup2(nullfd, 0);
dup2(nullfd, 1);
}
close(3);
closefrom(5);
while (1) {
char c;
int sock;
int pid;
int numfds = 1;
int res = receive_message(cfd, &c, sizeof(c), &sock, &numfds);
if (!res)
break;
if (res == -1)
exit(1);
assert(numfds == 1);
pid = fork();
if (pid == -1) {
perror("ulockmgr_server: fork");
close(sock);
continue;
}
if (pid == 0) {
close(cfd);
pid = fork();
if (pid == -1) {
perror("ulockmgr_server: fork");
_exit(1);
}
if (pid == 0)
process_owner(sock);
_exit(0);
}
waitpid(pid, NULL, 0);
close(sock);
}
return 0;
out_inval:
fprintf(stderr, "%s should be started by libulockmgr\n", argv[0]);
return 1;
}
+1339 -270
View File
File diff suppressed because it is too large Load Diff
+8 -5
View File
@@ -10,20 +10,20 @@ URL: https://github.com/trapexit/mergerfs
Source: mergerfs-%{version}.tar.gz
BuildRequires: gcc-c++
BuildRequires: libattr-devel
BuildRequires: fuse-devel
# rpmbuild driven by the Makefile uses git to generate a version number
BuildRequires: git
Requires: fuse
%global debug_package %{nil}
%prep
%setup -q
%description
mergerfs is similar to mhddfs, unionfs, and aufs. Like mhddfs in that it too
uses FUSE. Like aufs in that it provides multiple policies for how to handle
behavior.
mergerfs is a union filesystem geared towards simplifying storage and
management of files across numerous commodity storage devices. It is
similar to mhddfs, unionfs, and aufs.
%build
make %{?_smp_mflags}
@@ -36,6 +36,9 @@ make install PREFIX=%{_prefix} DESTDIR=%{buildroot}
%doc %{_mandir}/*
%changelog
* Fri Apr 26 2019 Antonio SJ Musumeci <trapexit@spawn.link>
- Update description
* Mon Jan 25 2016 Antonio SJ Musumeci <trapexit@spawn.link>
- Remove sbin files
+1 -4
View File
@@ -14,8 +14,7 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __ASSERT_HPP__
#define __ASSERT_HPP__
#pragma once
#define STATIC_ASSERT(cond) assert::StaticAssert< (cond) >()
#define STATIC_ARRAYLENGTH_ASSERT(array,size) STATIC_ASSERT(((sizeof(array)/sizeof(array[0]))==(size)))
@@ -29,5 +28,3 @@ namespace assert
struct StaticAssert<true>
{};
}
#endif
+222
View File
@@ -0,0 +1,222 @@
/*
ISC License
Copyright (c) 2018, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "branch.hpp"
#include "fs.hpp"
#include "fs_glob.hpp"
#include "str.hpp"
#include <fnmatch.h>
#include <string>
using std::string;
using std::vector;
bool
Branch::ro(void) const
{
return (mode == Branch::RO);
}
bool
Branch::nc(void) const
{
return (mode == Branch::NC);
}
bool
Branch::ro_or_nc(void) const
{
return ((mode == Branch::RO) ||
(mode == Branch::NC));
}
string
Branches::to_string(const bool mode_) const
{
string tmp;
for(size_t i = 0; i < size(); i++)
{
const Branch &branch = (*this)[i];
tmp += branch.path;
if(mode_)
{
tmp += '=';
switch(branch.mode)
{
default:
case Branch::RW:
tmp += "RW";
break;
case Branch::RO:
tmp += "RO";
break;
case Branch::NC:
tmp += "NC";
break;
}
}
tmp += ':';
}
if(*tmp.rbegin() == ':')
tmp.erase(tmp.size() - 1);
return tmp;
}
void
Branches::to_paths(vector<string> &vec_) const
{
for(size_t i = 0; i < size(); i++)
{
const Branch &branch = (*this)[i];
vec_.push_back(branch.path);
}
}
static
void
parse(const string &str_,
Branches &branches_)
{
string str;
Branch branch;
vector<string> globbed;
str = str_;
branch.mode = Branch::INVALID;
if(str::ends_with(str,"=RO"))
branch.mode = Branch::RO;
else if(str::ends_with(str,"=RW"))
branch.mode = Branch::RW;
else if(str::ends_with(str,"=NC"))
branch.mode = Branch::NC;
if(branch.mode != Branch::INVALID)
str.resize(str.size() - 3);
else
branch.mode = Branch::RW;
fs::glob(str,globbed);
fs::realpathize(globbed);
for(size_t i = 0; i < globbed.size(); i++)
{
branch.path = globbed[i];
branches_.push_back(branch);
}
}
void
Branches::set(const std::string &str_)
{
vector<string> paths;
clear();
str::split(paths,str_,':');
for(size_t i = 0; i < paths.size(); i++)
{
Branches branches;
parse(paths[i],branches);
insert(end(),
branches.begin(),
branches.end());
}
}
void
Branches::add_begin(const std::string &str_)
{
vector<string> paths;
str::split(paths,str_,':');
for(size_t i = 0; i < paths.size(); i++)
{
Branches branches;
parse(paths[i],branches);
insert(begin(),
branches.begin(),
branches.end());
}
}
void
Branches::add_end(const std::string &str_)
{
vector<string> paths;
str::split(paths,str_,':');
for(size_t i = 0; i < paths.size(); i++)
{
Branches branches;
parse(paths[i],branches);
insert(end(),
branches.begin(),
branches.end());
}
}
void
Branches::erase_begin(void)
{
erase(begin());
}
void
Branches::erase_end(void)
{
pop_back();
}
void
Branches::erase_fnmatch(const std::string &str_)
{
vector<string> patterns;
str::split(patterns,str_,':');
for(iterator i = begin(); i != end();)
{
int match = FNM_NOMATCH;
for(vector<string>::const_iterator pi = patterns.begin();
pi != patterns.end() && match != 0;
++pi)
{
match = ::fnmatch(pi->c_str(),i->path.c_str(),0);
}
i = ((match == 0) ? erase(i) : (i+1));
}
}
+36 -12
View File
@@ -1,5 +1,7 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
ISC License
Copyright (c) 2018, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -14,19 +16,41 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __OPENDIR_HPP__
#define __OPENDIR_HPP__
#pragma once
#include <string>
#include <vector>
namespace mergerfs
struct Branch
{
namespace fuse
{
int
opendir(const char *fusepath,
fuse_file_info *ffi);
}
}
enum Mode
{
INVALID,
RO,
RW,
NC
};
#endif
Mode mode;
std::string path;
bool ro(void) const;
bool nc(void) const;
bool ro_or_nc(void) const;
};
class Branches : public std::vector<Branch>
{
public:
std::string to_string(const bool mode_ = false) const;
void to_paths(std::vector<std::string> &vec_) const;
public:
void set(const std::string &str_);
void add_begin(const std::string &str_);
void add_end(const std::string &str_);
void erase_begin(void);
void erase_end(void);
void erase_fnmatch(const std::string &str_);
};
+1 -4
View File
@@ -14,8 +14,7 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __BUILDMAP_HPP__
#define __BUILDMAP_HPP__
#pragma once
#include <algorithm>
@@ -44,5 +43,3 @@ public:
private:
std::map<K,V> _map;
};
#endif
+2 -4
View File
@@ -14,10 +14,10 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __BUILDVECTOR_HPP__
#define __BUILDVECTOR_HPP__
#pragma once
#include <algorithm>
#include <vector>
template<typename V, bool SORT = false>
class buildvector
@@ -44,5 +44,3 @@ public:
private:
std::vector<V> _vector;
};
#endif
+30 -33
View File
@@ -22,41 +22,38 @@
#define CATEGORY(X) Category(Category::Enum::X,#X)
namespace mergerfs
const std::vector<Category> Category::_categories_ =
buildvector<Category,true>
(CATEGORY(invalid))
(CATEGORY(action))
(CATEGORY(create))
(CATEGORY(search));
const Category * const Category::categories = &_categories_[1];
const Category &Category::invalid = Category::categories[Category::Enum::invalid];
const Category &Category::action = Category::categories[Category::Enum::action];
const Category &Category::create = Category::categories[Category::Enum::create];
const Category &Category::search = Category::categories[Category::Enum::search];
const Category&
Category::find(const std::string &str)
{
const std::vector<Category> Category::_categories_ =
buildvector<Category,true>
(CATEGORY(invalid))
(CATEGORY(action))
(CATEGORY(create))
(CATEGORY(search));
for(int i = Enum::BEGIN; i != Enum::END; ++i)
{
if(categories[i] == str)
return categories[i];
}
const Category * const Category::categories = &_categories_[1];
return invalid;
}
const Category &Category::invalid = Category::categories[Category::Enum::invalid];
const Category &Category::action = Category::categories[Category::Enum::action];
const Category &Category::create = Category::categories[Category::Enum::create];
const Category &Category::search = Category::categories[Category::Enum::search];
const Category&
Category::find(const Category::Enum::Type i)
{
if(i >= Category::Enum::BEGIN &&
i < Category::Enum::END)
return categories[i];
const Category&
Category::find(const std::string &str)
{
for(int i = Enum::BEGIN; i != Enum::END; ++i)
{
if(categories[i] == str)
return categories[i];
}
return invalid;
}
const Category&
Category::find(const Category::Enum::Type i)
{
if(i >= Category::Enum::BEGIN &&
i < Category::Enum::END)
return categories[i];
return invalid;
}
return invalid;
}
+60 -66
View File
@@ -14,77 +14,71 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __CATEGORY_HPP__
#define __CATEGORY_HPP__
#pragma once
#include <string>
#include <vector>
namespace mergerfs
class Category
{
class Category
public:
struct Enum
{
public:
struct Enum
{
enum Type
{
invalid = -1,
BEGIN = 0,
action = BEGIN,
create,
search,
END
};
};
private:
Enum::Type _enum;
std::string _str;
public:
Category()
: _enum(invalid),
_str(invalid)
{
}
Category(const Enum::Type enum_,
const std::string &str_)
: _enum(enum_),
_str(str_)
{
}
public:
operator const Enum::Type() const { return _enum; }
operator const std::string&() const { return _str; }
operator const Category*() const { return this; }
bool operator==(const std::string &str_) const
{ return _str == str_; }
bool operator==(const Enum::Type enum_) const
{ return _enum == enum_; }
bool operator!=(const Category &r) const
{ return _enum != r._enum; }
bool operator<(const Category &r) const
{ return _enum < r._enum; }
public:
static const Category &find(const std::string&);
static const Category &find(const Enum::Type);
public:
static const std::vector<Category> _categories_;
static const Category * const categories;
static const Category &invalid;
static const Category &action;
static const Category &create;
static const Category &search;
enum Type
{
invalid = -1,
BEGIN = 0,
action = BEGIN,
create,
search,
END
};
};
}
#endif
private:
Enum::Type _enum;
std::string _str;
public:
Category()
: _enum(invalid),
_str(invalid)
{
}
Category(const Enum::Type enum_,
const std::string &str_)
: _enum(enum_),
_str(str_)
{
}
public:
operator const Enum::Type() const { return _enum; }
operator const std::string&() const { return _str; }
operator const Category*() const { return this; }
bool operator==(const std::string &str_) const
{ return _str == str_; }
bool operator==(const Enum::Type enum_) const
{ return _enum == enum_; }
bool operator!=(const Category &r) const
{ return _enum != r._enum; }
bool operator<(const Category &r) const
{ return _enum < r._enum; }
public:
static const Category &find(const std::string&);
static const Category &find(const Enum::Type);
public:
static const std::vector<Category> _categories_;
static const Category * const categories;
static const Category &invalid;
static const Category &action;
static const Category &create;
static const Category &search;
};
-106
View File
@@ -1,106 +0,0 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <fuse.h>
#include <string>
#include <vector>
#include "config.hpp"
#include "errno.hpp"
#include "fs_base_chmod.hpp"
#include "fs_path.hpp"
#include "rv.hpp"
#include "rwlock.hpp"
#include "ugid.hpp"
using std::string;
using std::vector;
using mergerfs::Policy;
static
int
_chmod_loop_core(const string *basepath,
const char *fusepath,
const mode_t mode,
const int error)
{
int rv;
string fullpath;
fs::path::make(basepath,fusepath,fullpath);
rv = fs::chmod(fullpath,mode);
return error::calc(rv,error,errno);
}
static
int
_chmod_loop(const vector<const string*> &basepaths,
const char *fusepath,
const mode_t mode)
{
int error;
error = -1;
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
{
error = _chmod_loop_core(basepaths[i],fusepath,mode,error);
}
return -error;
}
static
int
_chmod(Policy::Func::Action actionFunc,
const vector<string> &srcmounts,
const uint64_t minfreespace,
const char *fusepath,
const mode_t mode)
{
int rv;
vector<const string*> basepaths;
rv = actionFunc(srcmounts,fusepath,minfreespace,basepaths);
if(rv == -1)
return -errno;
return _chmod_loop(basepaths,fusepath,mode);
}
namespace mergerfs
{
namespace fuse
{
int
chmod(const char *fusepath,
mode_t mode)
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::get(fc);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _chmod(config.chmod,
config.srcmounts,
config.minfreespace,
fusepath,
mode);
}
}
}
-112
View File
@@ -1,112 +0,0 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <fuse.h>
#include <string>
#include <vector>
#include "config.hpp"
#include "errno.hpp"
#include "fs_base_chown.hpp"
#include "fs_path.hpp"
#include "rv.hpp"
#include "rwlock.hpp"
#include "ugid.hpp"
using std::string;
using std::vector;
using mergerfs::Policy;
using mergerfs::Config;
static
int
_chown_loop_core(const string *basepath,
const char *fusepath,
const uid_t uid,
const gid_t gid,
const int error)
{
int rv;
string fullpath;
fs::path::make(basepath,fusepath,fullpath);
rv = fs::lchown(fullpath,uid,gid);
return error::calc(rv,error,errno);
}
static
int
_chown_loop(const vector<const string*> &basepaths,
const char *fusepath,
const uid_t uid,
const gid_t gid)
{
int error;
error = -1;
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
{
error = _chown_loop_core(basepaths[i],fusepath,uid,gid,error);
}
return -error;
}
static
int
_chown(Policy::Func::Action actionFunc,
const vector<string> &srcmounts,
const uint64_t minfreespace,
const char *fusepath,
const uid_t uid,
const gid_t gid)
{
int rv;
vector<const string*> basepaths;
rv = actionFunc(srcmounts,fusepath,minfreespace,basepaths);
if(rv == -1)
return -errno;
return _chown_loop(basepaths,fusepath,uid,gid);
}
namespace mergerfs
{
namespace fuse
{
int
chown(const char *fusepath,
uid_t uid,
gid_t gid)
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::get(fc);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _chown(config.chown,
config.srcmounts,
config.minfreespace,
fusepath,
uid,
gid);
}
}
}
+168 -85
View File
@@ -14,103 +14,186 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "config.hpp"
#include "errno.hpp"
#include "fs.hpp"
#include "rwlock.hpp"
#include <string>
#include <vector>
#include <unistd.h>
#include <sys/stat.h>
#include "config.hpp"
#include "errno.hpp"
#include "fs.hpp"
#include "rwlock.hpp"
#define MINFREESPACE_DEFAULT (4294967295ULL)
#define POLICYINIT(X) X(policies[FuseFunc::Enum::X])
using std::string;
using std::vector;
namespace mergerfs
Config::Config()
: destmount(),
branches(),
branches_lock(),
minfreespace(MINFREESPACE_DEFAULT),
moveonenospc(false),
direct_io(false),
dropcacheonclose(false),
symlinkify(false),
symlinkify_timeout(3600),
nullrw(false),
ignorepponrename(false),
security_capability(true),
link_cow(false),
xattr(0),
statfs(StatFS::BASE),
statfs_ignore(StatFSIgnore::NONE),
posix_acl(false),
cache_symlinks(false),
cache_readdir(false),
async_read(true),
cache_files(CacheFiles::LIBFUSE),
fuse_msg_size(FUSE_MAX_MAX_PAGES),
POLICYINIT(access),
POLICYINIT(chmod),
POLICYINIT(chown),
POLICYINIT(create),
POLICYINIT(getattr),
POLICYINIT(getxattr),
POLICYINIT(link),
POLICYINIT(listxattr),
POLICYINIT(mkdir),
POLICYINIT(mknod),
POLICYINIT(open),
POLICYINIT(readlink),
POLICYINIT(removexattr),
POLICYINIT(rename),
POLICYINIT(rmdir),
POLICYINIT(setxattr),
POLICYINIT(symlink),
POLICYINIT(truncate),
POLICYINIT(unlink),
POLICYINIT(utimens),
controlfile("/.mergerfs")
{
Config::Config()
: destmount(),
srcmounts(),
srcmountslock(),
minfreespace(MINFREESPACE_DEFAULT),
moveonenospc(false),
direct_io(false),
dropcacheonclose(false),
POLICYINIT(access),
POLICYINIT(chmod),
POLICYINIT(chown),
POLICYINIT(create),
POLICYINIT(getattr),
POLICYINIT(getxattr),
POLICYINIT(link),
POLICYINIT(listxattr),
POLICYINIT(mkdir),
POLICYINIT(mknod),
POLICYINIT(open),
POLICYINIT(readlink),
POLICYINIT(removexattr),
POLICYINIT(rename),
POLICYINIT(rmdir),
POLICYINIT(setxattr),
POLICYINIT(symlink),
POLICYINIT(truncate),
POLICYINIT(unlink),
POLICYINIT(utimens),
controlfile("/.mergerfs")
{
pthread_rwlock_init(&srcmountslock,NULL);
pthread_rwlock_init(&branches_lock,NULL);
set_category_policy("action","all");
set_category_policy("create","epmfs");
set_category_policy("search","ff");
}
int
Config::set_func_policy(const string &fusefunc_,
const string &policy_)
{
const Policy *policy;
const FuseFunc *fusefunc;
fusefunc = FuseFunc::find(fusefunc_);
if(fusefunc == FuseFunc::invalid)
return (errno=ENODATA,-1);
policy = Policy::find(policy_);
if(policy == Policy::invalid)
return (errno=EINVAL,-1);
policies[(FuseFunc::Enum::Type)*fusefunc] = policy;
return 0;
}
int
Config::set_category_policy(const string &category_,
const string &policy_)
{
const Policy *policy;
const Category *category;
category = Category::find(category_);
if(category == Category::invalid)
return (errno=ENODATA,-1);
policy = Policy::find(policy_);
if(policy == Policy::invalid)
return (errno=EINVAL,-1);
for(int i = 0; i < FuseFunc::Enum::END; i++)
{
if(FuseFunc::fusefuncs[i] == (Category::Enum::Type)*category)
policies[(FuseFunc::Enum::Type)FuseFunc::fusefuncs[i]] = policy;
}
return 0;
}
set_category_policy("action","epall");
set_category_policy("create","epmfs");
set_category_policy("search","ff");
}
int
Config::set_func_policy(const string &fusefunc_,
const string &policy_)
{
const Policy *policy;
const FuseFunc *fusefunc;
fusefunc = FuseFunc::find(fusefunc_);
if(fusefunc == FuseFunc::invalid)
return (errno=ENODATA,-1);
policy = Policy::find(policy_);
if(policy == Policy::invalid)
return (errno=EINVAL,-1);
policies[(FuseFunc::Enum::Type)*fusefunc] = policy;
return 0;
}
int
Config::set_category_policy(const string &category_,
const string &policy_)
{
const Policy *policy;
const Category *category;
category = Category::find(category_);
if(category == Category::invalid)
return (errno=ENODATA,-1);
policy = Policy::find(policy_);
if(policy == Policy::invalid)
return (errno=EINVAL,-1);
for(int i = 0; i < FuseFunc::Enum::END; i++)
{
if(FuseFunc::fusefuncs[i] == (Category::Enum::Type)*category)
policies[(FuseFunc::Enum::Type)FuseFunc::fusefuncs[i]] = policy;
}
return 0;
}
Config::CacheFiles::operator int() const
{
return _data;
}
Config::CacheFiles::operator std::string() const
{
switch(_data)
{
case OFF:
return "off";
case PARTIAL:
return "partial";
case FULL:
return "full";
case AUTO_FULL:
return "auto-full";
case LIBFUSE:
return "libfuse";
case INVALID:
break;
}
return "";
}
Config::CacheFiles::CacheFiles()
: _data(INVALID)
{
}
Config::CacheFiles::CacheFiles(Config::CacheFiles::Enum data_)
: _data(data_)
{
}
bool
Config::CacheFiles::valid() const
{
return (_data != INVALID);
}
Config::CacheFiles&
Config::CacheFiles::operator=(const Config::CacheFiles::Enum data_)
{
_data = data_;
return *this;
}
Config::CacheFiles&
Config::CacheFiles::operator=(const std::string &data_)
{
if(data_ == "off")
_data = OFF;
else if(data_ == "partial")
_data = PARTIAL;
else if(data_ == "full")
_data = FULL;
else if(data_ == "auto-full")
_data = AUTO_FULL;
else if(data_ == "libfuse")
_data = LIBFUSE;
else
_data = INVALID;
return *this;
}
+138 -63
View File
@@ -14,83 +14,158 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __CONFIG_HPP__
#define __CONFIG_HPP__
#pragma once
#include "branch.hpp"
#include "fusefunc.hpp"
#include "policy.hpp"
#include "policy_cache.hpp"
#include <fuse.h>
#include <sys/stat.h>
#include <stdint.h>
#include <string>
#include <vector>
#include "policy.hpp"
#include "fusefunc.hpp"
#include <stdint.h>
#include <sys/stat.h>
namespace mergerfs
class Config
{
class Config
public:
struct StatFS
{
enum Enum
{
BASE,
FULL
};
};
struct StatFSIgnore
{
enum Enum
{
NONE,
RO,
NC
};
};
class CacheFiles
{
public:
Config();
enum Enum
{
INVALID = -1,
LIBFUSE,
OFF,
PARTIAL,
FULL,
AUTO_FULL
};
public:
int set_func_policy(const std::string &fusefunc_,
const std::string &policy_);
int set_category_policy(const std::string &category,
const std::string &policy);
CacheFiles();
CacheFiles(Enum);
public:
std::string destmount;
std::vector<std::string> srcmounts;
mutable pthread_rwlock_t srcmountslock;
uint64_t minfreespace;
bool moveonenospc;
bool direct_io;
bool dropcacheonclose;
operator int() const;
operator std::string() const;
public:
const Policy *policies[FuseFunc::Enum::END];
const Policy *&access;
const Policy *&chmod;
const Policy *&chown;
const Policy *&create;
const Policy *&getattr;
const Policy *&getxattr;
const Policy *&link;
const Policy *&listxattr;
const Policy *&mkdir;
const Policy *&mknod;
const Policy *&open;
const Policy *&readlink;
const Policy *&removexattr;
const Policy *&rename;
const Policy *&rmdir;
const Policy *&setxattr;
const Policy *&symlink;
const Policy *&truncate;
const Policy *&unlink;
const Policy *&utimens;
CacheFiles& operator=(const Enum);
CacheFiles& operator=(const std::string&);
public:
const std::string controlfile;
bool valid() const;
public:
static
const Config &
get(const fuse_context *fc)
{
return *((Config*)fc->private_data);
}
static
Config &
get_writable(void)
{
return (*((Config*)fuse_get_context()->private_data));
}
private:
Enum _data;
};
}
#endif
public:
Config();
public:
int set_func_policy(const std::string &fusefunc_,
const std::string &policy_);
int set_category_policy(const std::string &category_,
const std::string &policy_);
public:
std::string fsname;
std::string destmount;
Branches branches;
mutable pthread_rwlock_t branches_lock;
uint64_t minfreespace;
bool moveonenospc;
bool direct_io;
bool kernel_cache;
bool auto_cache;
bool dropcacheonclose;
bool symlinkify;
time_t symlinkify_timeout;
bool nullrw;
bool ignorepponrename;
bool security_capability;
bool link_cow;
int xattr;
StatFS::Enum statfs;
StatFSIgnore::Enum statfs_ignore;
bool posix_acl;
bool cache_symlinks;
bool cache_readdir;
bool async_read;
CacheFiles cache_files;
uint16_t fuse_msg_size;
public:
const Policy *policies[FuseFunc::Enum::END];
const Policy *&access;
const Policy *&chmod;
const Policy *&chown;
const Policy *&create;
const Policy *&getattr;
const Policy *&getxattr;
const Policy *&link;
const Policy *&listxattr;
const Policy *&mkdir;
const Policy *&mknod;
const Policy *&open;
const Policy *&readlink;
const Policy *&removexattr;
const Policy *&rename;
const Policy *&rmdir;
const Policy *&setxattr;
const Policy *&symlink;
const Policy *&truncate;
const Policy *&unlink;
const Policy *&utimens;
public:
mutable PolicyCache open_cache;
public:
const std::string controlfile;
public:
static
const
Config &
get(void)
{
const fuse_context *fc = fuse_get_context();
return get(fc);
}
static
const Config &
get(const fuse_context *fc)
{
return *((Config*)fc->private_data);
}
static
Config &
get_writable(void)
{
return (*((Config*)fuse_get_context()->private_data));
}
};
-144
View File
@@ -1,144 +0,0 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <fuse.h>
#include <string>
#include <vector>
#include "config.hpp"
#include "errno.hpp"
#include "fileinfo.hpp"
#include "fs_acl.hpp"
#include "fs_base_open.hpp"
#include "fs_clonepath.hpp"
#include "fs_path.hpp"
#include "rwlock.hpp"
#include "ugid.hpp"
using std::string;
using std::vector;
using namespace mergerfs;
static
inline
int
_create_core(const string &fullpath,
mode_t mode,
const mode_t umask,
const int flags)
{
if(!fs::acl::dir_has_defaults(fullpath))
mode &= ~umask;
return fs::open(fullpath,flags,mode);
}
static
int
_create_core(const string &existingpath,
const string &createpath,
const char *fusepath,
const char *fusedirpath,
const mode_t mode,
const mode_t umask,
const int flags,
uint64_t &fh)
{
int rv;
string fullpath;
if(createpath != existingpath)
{
const ugid::SetRootGuard ugidGuard;
rv = fs::clonepath(existingpath,createpath,fusedirpath);
if(rv == -1)
return -errno;
}
fs::path::make(&createpath,fusepath,fullpath);
rv = _create_core(fullpath,mode,umask,flags);
if(rv == -1)
return -errno;
fh = reinterpret_cast<uint64_t>(new FileInfo(rv));
return 0;
}
static
int
_create(Policy::Func::Search searchFunc,
Policy::Func::Create createFunc,
const vector<string> &srcmounts,
const uint64_t minfreespace,
const char *fusepath,
const mode_t mode,
const mode_t umask,
const int flags,
uint64_t &fh)
{
int rv;
string fullpath;
string fusedirpath;
const char *fusedirpathcstr;
vector<const string*> createpaths;
vector<const string*> existingpaths;
fusedirpath = fusepath;
fs::path::dirname(fusedirpath);
fusedirpathcstr = fusedirpath.c_str();
rv = searchFunc(srcmounts,fusedirpathcstr,minfreespace,existingpaths);
if(rv == -1)
return -errno;
rv = createFunc(srcmounts,fusedirpathcstr,minfreespace,createpaths);
if(rv == -1)
return -errno;
return _create_core(*existingpaths[0],*createpaths[0],
fusepath,fusedirpathcstr,
mode,umask,flags,fh);
}
namespace mergerfs
{
namespace fuse
{
int
create(const char *fusepath,
mode_t mode,
fuse_file_info *ffi)
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::get(fc);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _create(config.getattr,
config.create,
config.srcmounts,
config.minfreespace,
fusepath,
mode,
fc->umask,
ffi->flags,
ffi->fh);
}
}
}
+31
View File
@@ -0,0 +1,31 @@
/*
Copyright (c) 2017, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#pragma once
#include <string>
class DirInfo
{
public:
DirInfo(const char *fusepath_)
: fusepath(fusepath_)
{
}
public:
std::string fusepath;
};
+13 -11
View File
@@ -1,5 +1,7 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
ISC License
Copyright (c) 2019, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -14,17 +16,17 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __FLUSH_HPP__
#define __FLUSH_HPP__
#pragma once
namespace mergerfs
namespace endian
{
namespace fuse
static
inline
bool
is_big(void)
{
int
flush(const char *path,
fuse_file_info *fi);
}
}
const union { uint32_t i; char c[4]; } u = { 0x01000000 };
#endif
return u.c[0];
}
};
+1 -4
View File
@@ -14,8 +14,7 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __ERRNO_HPP__
#define __ERRNO_HPP__
#pragma once
#include <errno.h>
@@ -30,5 +29,3 @@
#if !defined(ENOATTR) && !defined(ENODATA)
#error "Neither ENOATTR or ENODATA defined: please contact mergerfs author with platform information"
#endif
#endif
-60
View File
@@ -1,60 +0,0 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#if FALLOCATE
#include <fuse.h>
#include "errno.hpp"
#include "fileinfo.hpp"
#include "fs_fallocate.hpp"
static
int
_fallocate(const int fd,
const int mode,
const off_t offset,
const off_t len)
{
int rv;
rv = fs::fallocate(fd,mode,offset,len);
return ((rv == -1) ? -errno : 0);
}
namespace mergerfs
{
namespace fuse
{
int
fallocate(const char *fusepath,
int mode,
off_t offset,
off_t len,
fuse_file_info *ffi)
{
FileInfo *fi = reinterpret_cast<FileInfo*>(ffi->fh);
return _fallocate(fi->fd,
mode,
offset,
len);
}
}
}
#endif
-33
View File
@@ -1,33 +0,0 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __FALLOCATE_HPP__
#define __FALLOCATE_HPP__
namespace mergerfs
{
namespace fuse
{
int
fallocate(const char *fusepath,
int mode,
off_t offset,
off_t len,
fuse_file_info *fi);
}
}
#endif
+84
View File
@@ -0,0 +1,84 @@
/* The MIT License
Copyright (C) 2012 Zilong Tan (eric.zltan@gmail.com)
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "fasthash.h"
// Compression function for Merkle-Damgard construction.
// This function is generated using the framework provided.
#define mix(h) ({ \
(h) ^= (h) >> 23; \
(h) *= 0x2127599bf4325c37ULL; \
(h) ^= (h) >> 47; })
uint64_t
fasthash64(const void *buf,
size_t len,
uint64_t seed)
{
const uint64_t m = 0x880355f21e6d1965ULL;
const uint64_t *pos = (const uint64_t *)buf;
const uint64_t *end = pos + (len / 8);
const unsigned char *pos2;
uint64_t h = seed ^ (len * m);
uint64_t v;
while (pos != end) {
v = *pos++;
h ^= mix(v);
h *= m;
}
pos2 = (const unsigned char*)pos;
v = 0;
switch (len & 7) {
case 7: v ^= (uint64_t)pos2[6] << 48;
case 6: v ^= (uint64_t)pos2[5] << 40;
case 5: v ^= (uint64_t)pos2[4] << 32;
case 4: v ^= (uint64_t)pos2[3] << 24;
case 3: v ^= (uint64_t)pos2[2] << 16;
case 2: v ^= (uint64_t)pos2[1] << 8;
case 1: v ^= (uint64_t)pos2[0];
h ^= mix(v);
h *= m;
}
return mix(h);
}
uint32_t
fasthash32(const void *buf,
size_t len,
uint32_t seed)
{
// the following trick converts the 64-bit hashcode to Fermat
// residue, which shall retain information from both the higher
// and lower parts of hashcode.
uint64_t h;
h = fasthash64(buf, len, seed);
return (h - (h >> 32));
}
+56
View File
@@ -0,0 +1,56 @@
/* The MIT License
Copyright (C) 2012 Zilong Tan (eric.zltan@gmail.com)
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef _FASTHASH_H
#define _FASTHASH_H
#include <stdint.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* fasthash32 - 32-bit implementation of fasthash
* @buf: data buffer
* @len: data size
* @seed: the seed
*/
uint32_t fasthash32(const void *buf, size_t len, uint32_t seed);
/**
* fasthash64 - 64-bit implementation of fasthash
* @buf: data buffer
* @len: data size
* @seed: the seed
*/
uint64_t fasthash64(const void *buf, size_t len, uint64_t seed);
#ifdef __cplusplus
}
#endif
#endif
+8 -6
View File
@@ -14,19 +14,21 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __FILEINFO_HPP__
#define __FILEINFO_HPP__
#pragma once
#include <string>
class FileInfo
{
public:
FileInfo(int _fd) :
fd(_fd)
FileInfo(const int fd_,
const char *fusepath_)
: fd(fd_),
fusepath(fusepath_)
{
}
public:
int fd;
std::string fusepath;
};
#endif
-31
View File
@@ -1,31 +0,0 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __FLOCK_HPP__
#define __FLOCK_HPP__
namespace mergerfs
{
namespace fuse
{
int
flock(const char *fusepath,
fuse_file_info *ffi,
int op);
}
}
#endif
+26 -125
View File
@@ -18,7 +18,6 @@
#include <vector>
#include <fcntl.h>
#include <glob.h>
#include <limits.h>
#include <stdint.h>
#include <stdlib.h>
@@ -27,106 +26,27 @@
#include "fs_attr.hpp"
#include "fs_base_realpath.hpp"
#include "fs_base_stat.hpp"
#include "fs_base_statvfs.hpp"
#include "fs_exists.hpp"
#include "fs_path.hpp"
#include "fs_statvfs_cache.hpp"
#include "fs_xattr.hpp"
#include "statvfs_util.hpp"
#include "str.hpp"
#include "success_fail.hpp"
using std::string;
using std::vector;
namespace fs
{
bool
exists(const string &path,
struct stat &st)
{
int rv;
rv = fs::lstat(path,st);
return LSTAT_SUCCEEDED(rv);
}
bool
exists(const string &path)
{
struct stat st;
return exists(path,st);
}
bool
info(const string &path,
bool &readonly,
uint64_t &spaceavail,
uint64_t &spaceused)
{
int rv;
struct statvfs st;
rv = fs::statvfs(path,st);
if(STATVFS_SUCCEEDED(rv))
{
readonly = StatVFS::readonly(st);
spaceavail = StatVFS::spaceavail(st);
spaceused = StatVFS::spaceused(st);
}
return STATVFS_SUCCEEDED(rv);
}
bool
readonly(const string &path)
{
int rv;
struct statvfs st;
rv = fs::statvfs(path,st);
return (STATVFS_SUCCEEDED(rv) && StatVFS::readonly(st));
}
bool
spaceavail(const string &path,
uint64_t &spaceavail)
{
int rv;
struct statvfs st;
rv = fs::statvfs(path,st);
if(STATVFS_SUCCEEDED(rv))
spaceavail = StatVFS::spaceavail(st);
return STATVFS_SUCCEEDED(rv);
}
bool
spaceused(const string &path,
uint64_t &spaceused)
{
int rv;
struct statvfs st;
rv = fs::statvfs(path,st);
if(STATVFS_SUCCEEDED(rv))
spaceused = StatVFS::spaceused(st);
return STATVFS_SUCCEEDED(rv);
}
void
findallfiles(const vector<string> &srcmounts,
findallfiles(const vector<string> &basepaths,
const char *fusepath,
vector<string> &paths)
{
string fullpath;
for(size_t i = 0, ei = srcmounts.size(); i != ei; i++)
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
{
fs::path::make(&srcmounts[i],fusepath,fullpath);
fullpath = fs::path::make(basepaths[i],fusepath);
if(!fs::exists(fullpath))
continue;
@@ -136,8 +56,8 @@ namespace fs
}
int
findonfs(const vector<string> &srcmounts,
const char *fusepath,
findonfs(const vector<string> &basepaths,
const string &fusepath,
const int fd,
string &basepath)
{
@@ -146,23 +66,23 @@ namespace fs
string fullpath;
struct stat st;
rv = fs::fstat(fd,st);
if(FSTAT_FAILED(rv))
rv = fs::fstat(fd,&st);
if(rv == -1)
return -1;
dev = st.st_dev;
for(int i = 0, ei = srcmounts.size(); i != ei; i++)
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
{
fs::path::make(&srcmounts[i],fusepath,fullpath);
fullpath = fs::path::make(basepaths[i],fusepath);
rv = fs::lstat(fullpath,st);
if(FSTAT_FAILED(rv))
rv = fs::lstat(fullpath,&st);
if(rv == -1)
continue;
if(st.st_dev != dev)
continue;
basepath = srcmounts[i];
basepath = basepaths[i];
return 0;
}
@@ -170,31 +90,6 @@ namespace fs
return (errno=ENOENT,-1);
}
void
glob(const vector<string> &patterns,
vector<string> &strs)
{
int flags;
size_t veclen;
glob_t gbuf = {0};
veclen = patterns.size();
if(veclen == 0)
return;
flags = 0;
glob(patterns[0].c_str(),flags,NULL,&gbuf);
flags = GLOB_APPEND;
for(size_t i = 1; i < veclen; i++)
glob(patterns[i].c_str(),flags,NULL,&gbuf);
for(size_t i = 0; i < gbuf.gl_pathc; ++i)
strs.push_back(gbuf.gl_pathv[i]);
globfree(&gbuf);
}
void
realpathize(vector<string> &strs)
{
@@ -218,24 +113,30 @@ namespace fs
return ::fcntl(fd,F_GETFL,0);
}
int
setfl(const int fd,
const mode_t mode)
{
return ::fcntl(fd,F_SETFL,mode);
}
int
mfs(const vector<string> &basepaths,
const uint64_t minfreespace,
string &path)
{
fsblkcnt_t mfs;
int rv;
uint64_t mfs;
uint64_t spaceavail;
const string *mfsbasepath;
mfs = 0;
mfsbasepath = NULL;
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
{
uint64_t spaceavail;
const string &basepath = basepaths[i];
if(!fs::spaceavail(basepath,spaceavail))
rv = fs::statvfs_cache_spaceavail(basepaths[i],&spaceavail);
if(rv == -1)
continue;
if(spaceavail < minfreespace)
continue;
if(spaceavail <= mfs)
+17 -37
View File
@@ -14,12 +14,12 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __FS_HPP__
#define __FS_HPP__
#pragma once
#include <string>
#include <vector>
#include <fcntl.h>
#include <stdint.h>
namespace fs
@@ -27,42 +27,22 @@ namespace fs
using std::string;
using std::vector;
bool exists(const string &path,
struct stat &st);
bool exists(const string &path);
void findallfiles(const vector<string> &basepaths_,
const char *fusepath_,
vector<string> &paths_);
bool info(const string &path,
bool &readonly,
uint64_t &spaceavail,
uint64_t &spaceused);
int findonfs(const vector<string> &basepaths_,
const string &fusepath_,
const int fd_,
string &basepath_);
bool readonly(const string &path);
void realpathize(vector<string> &strs_);
bool spaceavail(const string &path,
uint64_t &spaceavail);
int getfl(const int fd_);
int setfl(const int fd_,
const mode_t mode_);
bool spaceused(const string &path,
uint64_t &spaceavail);
void findallfiles(const vector<string> &srcmounts,
const char *fusepath,
vector<string> &paths);
int findonfs(const vector<string> &srcmounts,
const char *fusepath,
const int fd,
string &basepath);
void glob(const vector<string> &patterns,
vector<string> &strs);
void realpathize(vector<string> &strs);
int getfl(const int fd);
int mfs(const vector<string> &srcs,
const uint64_t minfreespace,
string &path);
};
#endif // __FS_HPP__
int mfs(const vector<string> &srcs_,
const uint64_t minfreespace_,
string &path_);
}
+3 -3
View File
@@ -28,12 +28,12 @@ namespace fs
namespace acl
{
bool
dir_has_defaults(const std::string &fullpath)
dir_has_defaults(const std::string &fullpath_)
{
int rv;
std::string dirpath = fullpath;
std::string dirpath;
fs::path::dirname(dirpath);
dirpath = fs::path::dirname(&fullpath_);
rv = fs::lgetxattr(dirpath,POSIX_ACL_DEFAULT_XATTR,NULL,0);
+3 -1
View File
@@ -16,6 +16,8 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#pragma once
#include <string>
namespace fs
@@ -23,6 +25,6 @@ namespace fs
namespace acl
{
bool
dir_has_defaults(const std::string &fullpath);
dir_has_defaults(const std::string &fullpath_);
}
}
+5 -10
View File
@@ -14,8 +14,7 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __FS_ATTR_HPP__
#define __FS_ATTR_HPP__
#pragma once
#include <string>
@@ -23,13 +22,9 @@ namespace fs
{
namespace attr
{
using std::string;
int copy(const int fdin,
const int fdout);
int copy(const string &from,
const string &to);
int copy(const int fdin_,
const int fdout_);
int copy(const std::string &from_,
const std::string &to_);
}
}
#endif // __FS_ATTR_HPP__
+14 -2
View File
@@ -35,7 +35,13 @@ namespace fs
get_fs_ioc_flags(const int fd,
int &flags)
{
return fs::ioctl(fd,FS_IOC_GETFLAGS,(void*)&flags);
int rv;
rv = fs::ioctl(fd,FS_IOC_GETFLAGS,(void*)&flags);
if((rv == -1) && (errno == EINVAL))
errno = ENOTSUP;
return rv;
}
static
@@ -68,7 +74,13 @@ namespace fs
set_fs_ioc_flags(const int fd,
const int flags)
{
return fs::ioctl(fd,FS_IOC_SETFLAGS,(void*)&flags);
int rv;
rv = fs::ioctl(fd,FS_IOC_SETFLAGS,(void*)&flags);
if((rv == -1) && (errno == EINVAL))
errno = ENOTSUP;
return rv;
}
static
+2 -2
View File
@@ -26,14 +26,14 @@ namespace fs
copy(const int fdin,
const int fdout)
{
return ENOTSUP;
return (errno=ENOTSUP,-1);
}
int
copy(const std::string &from,
const std::string &to)
{
return ENOTSUP;
return (errno=ENOTSUP,-1);
}
}
}
+13 -16
View File
@@ -16,8 +16,7 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __FS_BASE_ACCESS_HPP__
#define __FS_BASE_ACCESS_HPP__
#pragma once
#include <string>
@@ -29,32 +28,30 @@ namespace fs
static
inline
int
access(const int dirfd,
const std::string &path,
const int mode,
const int flags)
access(const int dirfd_,
const std::string &path_,
const int mode_,
const int flags_)
{
return ::faccessat(dirfd,path.c_str(),mode,flags);
return ::faccessat(dirfd_,path_.c_str(),mode_,flags_);
}
static
inline
int
access(const std::string &path,
const int mode,
const int flags)
access(const std::string &path_,
const int mode_,
const int flags_)
{
return fs::access(AT_FDCWD,path,mode,flags);
return fs::access(AT_FDCWD,path_,mode_,flags_);
}
static
inline
int
eaccess(const std::string &path,
const int mode)
eaccess(const std::string &path_,
const int mode_)
{
return fs::access(path,mode,AT_EACCESS);
return fs::access(path_,mode_,AT_EACCESS);
}
}
#endif
+11 -58
View File
@@ -16,13 +16,12 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __FS_BASE_CHMOD_HPP__
#define __FS_BASE_CHMOD_HPP__
#include <sys/stat.h>
#pragma once
#include "fs_base_stat.hpp"
#include <sys/stat.h>
#define MODE_BITS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
namespace fs
@@ -30,81 +29,35 @@ namespace fs
static
inline
int
chmod(const std::string &path,
const mode_t mode)
chmod(const std::string &path_,
const mode_t mode_)
{
return ::chmod(path.c_str(),mode);
return ::chmod(path_.c_str(),mode_);
}
static
inline
int
fchmod(const int fd,
const mode_t mode)
{
return ::fchmod(fd,mode);
}
static
inline
int
fchmod(const int fd,
const struct stat &st)
{
return ::fchmod(fd,st.st_mode);
}
static
inline
int
chmod_check_on_error(const std::string &path,
const mode_t mode)
chmod_check_on_error(const std::string &path_,
const mode_t mode_)
{
int rv;
rv = fs::chmod(path,mode);
rv = fs::chmod(path_,mode_);
if(rv == -1)
{
int error;
struct stat st;
error = errno;
rv = fs::stat(path,st);
rv = fs::stat(path_,&st);
if(rv == -1)
return -1;
if((st.st_mode & MODE_BITS) != (mode & MODE_BITS))
return (errno=error,-1);
}
return 0;
}
static
inline
int
fchmod_check_on_error(const int fd,
const struct stat &st)
{
int rv;
rv = fs::fchmod(fd,st);
if(rv == -1)
{
int error;
struct stat tmpst;
error = errno;
rv = fs::fstat(fd,tmpst);
if(rv == -1)
return -1;
if((st.st_mode & MODE_BITS) != (tmpst.st_mode & MODE_BITS))
if((st.st_mode & MODE_BITS) != (mode_ & MODE_BITS))
return (errno=error,-1);
}
return 0;
}
}
#endif
+23 -72
View File
@@ -16,8 +16,9 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __FS_BASE_CHOWN_HPP__
#define __FS_BASE_CHOWN_HPP__
#pragma once
#include "fs_base_stat.hpp"
#include <string>
@@ -25,120 +26,70 @@
#include <sys/types.h>
#include <unistd.h>
#include "fs_base_stat.hpp"
namespace fs
{
static
inline
int
chown(const std::string &path,
const uid_t uid,
const gid_t gid)
chown(const std::string &path_,
const uid_t uid_,
const gid_t gid_)
{
return ::chown(path.c_str(),uid,gid);
return ::chown(path_.c_str(),uid_,gid_);
}
static
inline
int
chown(const std::string &path,
const struct stat &st)
chown(const std::string &path_,
const struct stat &st_)
{
return fs::chown(path,st.st_uid,st.st_gid);
return fs::chown(path_,st_.st_uid,st_.st_gid);
}
static
inline
int
lchown(const std::string &path,
const uid_t uid,
const gid_t gid)
lchown(const std::string &path_,
const uid_t uid_,
const gid_t gid_)
{
return ::lchown(path.c_str(),uid,gid);
return ::lchown(path_.c_str(),uid_,gid_);
}
static
inline
int
lchown(const std::string &path,
const struct stat &st)
lchown(const std::string &path_,
const struct stat &st_)
{
return fs::lchown(path,st.st_uid,st.st_gid);
return fs::lchown(path_,st_.st_uid,st_.st_gid);
}
static
inline
int
fchown(const int fd,
const uid_t uid,
const gid_t gid)
{
return ::fchown(fd,uid,gid);
}
static
inline
int
fchown(const int fd,
const struct stat &st)
{
return fs::fchown(fd,st.st_uid,st.st_gid);
}
static
inline
int
lchown_check_on_error(const std::string &path,
const struct stat &st)
lchown_check_on_error(const std::string &path_,
const struct stat &st_)
{
int rv;
rv = fs::lchown(path,st);
rv = fs::lchown(path_,st_);
if(rv == -1)
{
int error;
struct stat tmpst;
error = errno;
rv = fs::lstat(path,tmpst);
rv = fs::lstat(path_,&tmpst);
if(rv == -1)
return -1;
if((st.st_uid != tmpst.st_uid) ||
(st.st_gid != tmpst.st_gid))
return (errno=error,-1);
}
return 0;
}
static
inline
int
fchown_check_on_error(const int fd,
const struct stat &st)
{
int rv;
rv = fs::fchown(fd,st);
if(rv == -1)
{
int error;
struct stat tmpst;
error = errno;
rv = fs::fstat(fd,tmpst);
if(rv == -1)
return -1;
if((st.st_uid != tmpst.st_uid) ||
(st.st_gid != tmpst.st_gid))
if((st_.st_uid != tmpst.st_uid) ||
(st_.st_gid != tmpst.st_gid))
return (errno=error,-1);
}
return 0;
}
}
#endif
+3 -6
View File
@@ -16,8 +16,7 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __FS_BASE_CLOSE_HPP__
#define __FS_BASE_CLOSE_HPP__
#pragma once
#include <unistd.h>
@@ -26,10 +25,8 @@ namespace fs
static
inline
int
close(const int fd)
close(const int fd_)
{
return ::close(fd);
return ::close(fd_);
}
}
#endif
+3 -6
View File
@@ -16,8 +16,7 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __FS_BASE_CLOSEDIR_HPP__
#define __FS_BASE_CLOSEDIR_HPP__
#pragma once
#include <dirent.h>
#include <sys/types.h>
@@ -27,10 +26,8 @@ namespace fs
static
inline
int
closedir(DIR *dirp)
closedir(DIR *dirp_)
{
return ::closedir(dirp);
return ::closedir(dirp_);
}
}
#endif

Some files were not shown because too many files have changed in this diff Show More