1684 Commits

Author SHA1 Message Date
b56f9d349c Temporary test error workaround in Ubuntu 25.10 2025-10-23 02:38:13 +09:00
9da9db069c Change CI test macos from macos-13 to macos-14 2025-10-20 06:23:32 +09:00
11a362939f Temporary handling of atime/ctime in test for Ubuntu25.10 2025-10-16 06:50:04 +09:00
49ab488f88 Add missing parallelism to memory tests (#2744) 2025-10-14 19:13:50 +09:00
5cce8a4ceb Upgrade CI to Fedora 43 (#2743) 2025-10-14 19:06:45 +09:00
b147c66c1b Fix typos (#2742) 2025-10-14 19:04:34 +09:00
423683825a Add missing diffutils for openSUSE Leap CI, as 16.0 misses cmp otherwise 2025-10-14 14:19:12 +09:00
f364450dfc Add openSUSE Leap 16.0 to the CI 2025-10-14 14:19:12 +09:00
b2e318c5c7 Added a flag to prevent stats cache expiration checks 2025-10-14 01:40:03 +09:00
52b263b99c Improved handling of XML parser errors 2025-10-13 13:36:40 +09:00
a9b9631c5c Fixed to not call xmlReadMemory if data length is 0 2025-10-12 04:18:08 +09:00
2cb869dfd2 The Truncate method of the StaCache class has been consolidated (#2729) 2025-10-11 02:13:49 +09:00
52835103f1 Upgrade CI to Ubuntu 25.10 2025-10-10 02:27:52 +09:00
ba386a8d7a Changed StatCache code and Improved small performance 2025-10-10 02:10:00 +09:00
c719e36f91 Fixed negative stat cache data was not working 2025-10-10 02:09:19 +09:00
735fe9352a Fixed Stat cache expire check processing (#2708) 2025-10-04 02:20:07 +09:00
4513e4f700 Use rockylinux/rockylinux instead of rockylinux (#2734)
The latter is stuck on 9.3 and 8.9 instead of the latest 9.6 and 8.10:

https://hub.docker.com/_/rockylinux

Co-authored-by: Takeshi Nakatani <ggtakec@gmail.com>
2025-10-04 00:59:14 +09:00
37e593aeb0 Changed file stat times(a/c/mtime) management 2025-10-03 13:59:41 +09:00
60fb557f14 Improved stat cache efficiency by not delete but only register 2025-09-11 17:20:40 +09:00
b7b5a108c2 Separate pjdfstest tests by command to make the log units smaller 2025-09-09 05:38:44 +09:00
0bf901eff7 Fixed test_external_modification test for MacOS 2025-09-02 05:20:04 +09:00
8408af8695 Replaced the free call with std::string 2025-08-31 02:34:36 +09:00
29c9e50f4e Remove unused aws-cli in alpine (#2727) 2025-08-31 00:00:49 +09:00
8cf28d71b8 Consolidate dnf calls for static-checks (#2726) 2025-08-31 00:00:10 +09:00
709cdfc604 Check integrity of downloaded binaries (#2723)
Usually package managers perform this check but we need to do it
ourselves for custom binaries.
2025-08-30 23:59:22 +09:00
eaa2a90a56 Deduplicate CentOS 9 and 10 (#2718)
EPEL is no longer required.
2025-08-30 23:56:49 +09:00
f1e836c725 Only install clang in MemoryTest task (#2719) 2025-08-30 23:55:57 +09:00
ff2080a39e Centralize C++ version in Makefiles (#2713) 2025-08-30 16:49:51 +09:00
1366f582b1 Replace sstream header with iosfwd in headers (#2712)
The latter is smaller and sufficient for parameters.
2025-08-30 16:47:00 +09:00
03583f3424 Upgrade to S3Proxy 2.7.0 (#2656)
Release notes:
https://github.com/gaul/s3proxy/releases/tag/s3proxy-2.6.0
https://github.com/gaul/s3proxy/releases/tag/s3proxy-2.7.0
2025-08-30 16:45:02 +09:00
fcaacd5397 Remove ut_test.py (#2722)
pjdfstest supersedes this.
2025-08-30 16:37:46 +09:00
4b46b7a811 Only install binaries in static-checks task (#2717)
Also remove outdated version checks.
2025-08-30 16:34:26 +09:00
e55c37ddab Clean up Valgrind installation (#2716) 2025-08-30 16:18:03 +09:00
0448ff460b Add S3 operation performance counters (#2715)
These can be used to evaluate changes like #2707.  Ideally tests could
assert how many operations they expect although this will require a
localhost HTTP server.
2025-08-30 16:13:30 +09:00
28771e5757 Changed to use rename when serializing to FileCacheStat 2025-08-30 01:21:13 +09:00
da17cace4f Fixed test_update_time_chown in test (#2720) 2025-08-29 03:11:18 +09:00
87d7a5822e Use curl instead of AWS CLI (#2689)
The latter starts up significantly slower which impedes integration
test times.  curl has some limitations, e.g., no SSE support.
2025-08-28 08:36:07 +09:00
e8b5a4109a Remove unused pip dependency (#2711)
df7bbb28d5 removed the use of this.
Also convert string to an array to reduce merge conflicts and
alphabetize packages for readability.
2025-08-27 08:25:38 +09:00
bae0facba3 Changed to serialize CacheFileStat after flushing a file 2025-08-26 16:54:39 +09:00
ecdcb4a836 Fixed unnecessary conversion to in DirStatCache::TruncateCacheHasLock (#2706) 2025-08-22 19:57:36 +09:00
066a2f8fa6 Added DirStatCache::GetChildLeafNameHasLock method 2025-08-22 06:48:06 +09:00
629207791e Remove unused S3FS_PTHREAD_ERRORCHECK (#2703) 2025-08-21 20:40:54 +09:00
b411e40d6b Add Debian trixie (#2702) 2025-08-21 20:36:17 +09:00
b1b9fb55d9 Use junk_data instead of urandom (#2700)
The latter seems to block on macOS sometimes.
2025-08-21 20:34:30 +09:00
666fea3d26 Remove unneeded x-prefix in comparisons
Found via shellcheck.  Reference:

https://www.shellcheck.net/wiki/SC2268
2025-08-21 06:11:03 +09:00
7112471a80 small spelling fix: 'no' to 'not' 2025-08-03 01:36:10 +09:00
50bb76f968 Remove S3FS_MALLOC_TRIM (#2699)
42b74c9d2e introduced this flag but it
is not clear that this behavior is required with recent libxml2
version.
2025-08-01 10:47:58 +09:00
c78517d410 Convert #if defined to #ifdef where possible (#2698)
Suggested by clang-tidy.
2025-08-01 10:43:44 +09:00
57b5d367f2 Deduplicate case-insensitive functors (#2697) 2025-07-29 22:28:06 +09:00
41ef4b6495 Convert s3fs_log_level to a strong enum (#2695) 2025-07-29 22:26:53 +09:00
0c559778bb Fixed typos in PR #2681 2025-07-29 10:53:24 +09:00
5a2a7ca4db Refactor to change StatCache class and add StatCacheNode classes 2025-07-25 03:45:27 +09:00
8faebbc7fc Add Rocky Linux 10 to CI (#2688) 2025-06-29 11:44:18 +09:00
8d68b8a03c Refactor to move functions and its declarations to appropriate files 2025-06-27 15:28:44 +09:00
97659c41f2 Fixed bugs in removing xattrs func and and test for it 2025-06-27 03:16:32 +09:00
b624596685 Simplify temporary file creation via mktemp (#2691)
Previously this used /dev/urandom which does not guarantee uniqueness
and sometimes blocked on macOS.  References #2690.
2025-06-26 19:05:16 +09:00
be28fbc7b8 Refactor StatCache words from NoObject to Negative 2025-06-10 10:36:48 +09:00
778059279b Upgrade CI to Alpine 3.22 2025-06-09 21:11:34 +09:00
5bc46ff1ba Removed the RUN_DIR variable which is no longer global 2025-06-09 21:10:42 +09:00
47231fc5fb Disable new S3 checksums for S3Proxy compatibility (#2686)
References aws/aws-cli#9214.
2025-06-09 19:31:46 +09:00
f1a954cbcb Refactor StatCache truncate processing 2025-06-08 23:51:31 +09:00
c620262d3d Fixed s3fs_flush to update pending meta for macos and nomultipart mode 2025-06-08 22:05:50 +09:00
63402bb556 Fixed the random string generation in test script for macos 2025-06-08 22:03:56 +09:00
c869b3996f Improve error handling (#2671)
Found via C++17 [[nodiscard]].
2025-06-07 14:58:06 +09:00
0e5bccc20b Simplify temporary file handling in CI scripts (#2680) 2025-06-07 14:56:32 +09:00
872f53d35a Remove Ubuntu 20.04 from CI (#2677)
This is EOL:
https://ubuntu.com/blog/ubuntu-20-04-lts-end-of-life-standard-support-is-coming-to-an-end-heres-how-to-prepare
2025-06-07 14:45:33 +09:00
109c968baa Changed some INFO level log messages to DBG level 2025-06-07 00:16:44 +09:00
3d6975b369 Fixed a bug when changing fdentity to a temporary path 2025-05-22 03:04:03 +09:00
f2542f22fe Require C++14 (#2596)
This only has some minor additions of std::make_unique, digits
separators, std::string literals, and more flexible constexpr.
References #2469.
2025-05-18 12:34:53 +09:00
3421025074 Use region instead of endpoint for configuration (#2669)
This is more consistent with the AWS docs.  Generally endpoint refers
to an HTTP URL not just the region.  Fixes #2668.
2025-05-18 10:49:35 +09:00
43f49b15e8 Reduce use of awk in tests (#2662) 2025-04-20 10:03:07 +09:00
093d223799 Use Fedora 42 for other CI functions (#2661) 2025-04-20 09:59:52 +09:00
853404a3ce Upgrade Alpine, OpenSuSE, Rocky, and Ubuntu to Java 21 (#2660) 2025-04-19 09:24:14 +09:00
30f9378dec Upgrade CI to Ubuntu 25.04 (#2659) 2025-04-19 09:21:39 +09:00
e083825f55 Upgrade CI to Fedora 42 (#2658)
Simplify argument parsing with cut to work around lack of awk.
2025-04-18 23:45:07 +09:00
22ca6ba6ee Updated CI test result for macos about updating xattr 2025-04-03 23:48:48 +09:00
04a82583d1 A case of HEAD response for mp is different on compatible storage 2025-04-02 23:04:27 -07:00
ad4646f027 Ask for the provider on support requests (#2652) 2025-04-02 22:59:03 +09:00
bfd27460cc Update COMPILATION.md
fix typo
2025-03-18 22:00:26 -07:00
ee1ff8ba75 Update COMPILATION.md
add hint for windows compilation
2025-03-18 22:00:26 -07:00
885b1efac6 change the way to get existing fdentity to optimize concurrent IO performance (#2623)
* change the way to get existing fdentity

* fix compiling err for ver > 1.91

* use GetROPath instead of GetPath

* compare FdEntity::ro_path first in FdEntity::GetFdEntityHasLock()

---------

Co-authored-by: fangqianan.fqa <fangqianan.fqa@alibaba-inc.com>
2025-03-01 01:56:07 +09:00
e63fe7ec65 Added backup variable for fdcache entity path (#2637) 2025-02-15 12:19:58 +09:00
dc92b1b087 Remove unneeded uses of std::map::operator[] (#2642)
These unintentionally mutate the map.  Script suggested by @danmar.
2025-02-09 11:21:44 +09:00
edf4141ad6 Updated to the new issue template workflow 2025-01-26 11:51:10 -08:00
dd4f1395ca Run passing tests from pjdfstest (#1882)
This downloads a tarball by hash instead of using a submodule.
References #1589.
2025-01-19 10:26:40 +09:00
84dcf34e2c Fixed refactoring mistakes about loading IAM credentials 2025-01-19 03:24:30 +09:00
b679e1db98 Fixed memory leak found by valgrind 2025-01-19 03:22:11 +09:00
be183c0323 Pin AWS CLI to work around S3Proxy limitation (#2633)
Also specify architecture to allow future ARM64 CI to work.
2025-01-18 10:56:18 +09:00
3df1195ae5 Expand clang-tidy CI target to all static-checks (#2625)
Relocate cppcheck and Shellcheck into a single CI target instead of
running them as part of all distributions.  While this modestly
reduces run-time by about 20 seconds, more importantly it avoids
workarounds for older checker versions and simplifies the code.
2025-01-03 15:04:58 +09:00
cd41bddd1e Upgrade to S3Proxy 2.5.0 (#2627)
Release notes:

https://github.com/gaul/s3proxy/releases/tag/s3proxy-2.5.0
2025-01-03 15:01:15 +09:00
87874caf95 Remove double free in DestroyCurlShareHandle (#2626)
ShareHandles.erase implicitly calls this via the unique_ptr
destructor.
2025-01-03 14:59:06 +09:00
b83c2852b8 Upgrade CI to Alpine 3.21 (#2620) 2024-12-15 10:19:29 +09:00
5e39eff403 Remove explicit std::string constructors (#2619)
char * automatically convert via the implicit std::string constructor.
2024-12-15 10:18:44 +09:00
6c77cd8780 Fixed a bug in check_service_req_threadworker 2024-12-15 09:51:42 +09:00
669cba3240 Address some 32-bit warnings (#2615) 2024-12-01 10:32:28 +09:00
d4f3fb01fc Make some methods const (#2614)
Found via cppcheck --inconclusive.
2024-12-01 10:31:03 +09:00
65e4aef2a1 Prefer C++-style casts over C-style casts (#2599)
The former are easier to identify.  Found via clang-tidy.

Co-authored-by: Takeshi Nakatani <ggtakec@gmail.com>
2024-12-01 10:29:08 +09:00
d13396127c Delete Semaphore copy and move methods (#2613)
This matches the macOS implementation.
2024-12-01 10:28:50 +09:00
990d2e0074 Add top-level clang-tidy make target 2024-11-30 03:59:40 +09:00
61abf80197 Organized multi-threading related options 2024-11-29 05:13:06 +09:00
956e8c5750 Added new class for curl share handle
Added new class for curl share handle.
And, paired the curl handle(S3fsCurl) with the worker thread.
Changed that each thread has its own SSL session cache to prevent data
races.
So OpenSSL suppression for ThreadSanitizer is no longer necessary, so
reverted it.
2024-11-28 03:40:40 +09:00
bfc3ea767a Removed last use of S3fsMultiCurl and changed those thread handling 2024-11-26 10:47:03 +09:00
499577c2a9 Refactored for standardizing content and copy handling for Multipart Upload 2024-11-25 05:48:38 +09:00
143284b2f3 Upgrade to S3Proxy 2.4.1 (#2433)
This transitions to the transient-nio2 storage backend which should
address a race condition with getBlob and be easier to work with in
the future.  Release notes:

https://github.com/gaul/s3proxy/releases/tag/s3proxy-2.4.1
https://github.com/gaul/s3proxy/releases/tag/s3proxy-2.4.0
https://github.com/gaul/s3proxy/releases/tag/s3proxy-2.3.0
https://github.com/gaul/s3proxy/releases/tag/s3proxy-2.2.0
https://github.com/gaul/s3proxy/releases/tag/s3proxy-2.1.0
2024-11-24 22:27:24 +09:00
7410b95db2 Refactored parallel get object request 2024-11-23 02:22:27 +09:00
86b5c9d88e Refactored multipart put head request 2024-11-16 09:35:23 +09:00
a1e47bc287 Changed multiple Head requests from S3fsMultiCurl to ThreadPoolMan 2024-11-14 07:41:03 +09:00
efc23316e9 Refactored single type requests to use through ThreadPoolMan 2024-11-12 09:08:14 +09:00
a680d3e138 Removed CurlHandlerPool and simplified it
Removed CurlHandlerPool and simplified it.
And against data race in OpenSSL, temporarily changed to not use Sessin cache.
2024-11-12 07:33:04 +09:00
cc29bea81b Call std::get_time instead of strptime (#2598)
This reduces the Windows-specific code.
2024-11-09 19:28:40 +09:00
af0d7ba45e Ensure fdent_data_lock is acquired after fdent_lock (#2595) 2024-11-09 19:28:13 +09:00
17d0970244 Changed the macOS Github Actions runner image to macos-13
Changed the macos Github Actions runner image to macos-13, and
avoided extended attribute error when copying with macos-fuse-t.
2024-11-07 16:51:53 +09:00
45b32046cd Consolidate lower and upper logic (#2594) 2024-11-06 00:07:12 +09:00
a101b88114 Compare case-insensitively instead of copying (#2593)
Also remove some code duplication.
2024-11-06 00:05:05 +09:00
d9ccdc4fce Look up header values directly (#2592)
stat_cache_entry::meta uses a case-insensitive comparator so there is
no need to loop over each entry to compare each key with lowercase.
2024-11-05 07:16:19 +09:00
7a989a58a0 Remove expensive log message during s3fs_getxattr (#2590) 2024-11-05 00:00:58 +09:00
82f694e473 Avoid unneeded std::string copies (#2589) 2024-11-04 23:59:54 +09:00
9a155c81a7 Enable clang-analyzer (#2588)
Also fix a few smaller issues.
2024-11-04 23:58:43 +09:00
9b888fa9b3 Fixed readdir bug with objects receiving EPERM on HEAD request 2024-11-04 15:25:12 +09:00
ef6c213471 Bypassed test_extended_attributes test on MacOS 2024-11-03 08:56:48 +09:00
90ea57b99b Add Fedora 41 and remove Fedora 39 from CI (#2580) 2024-11-02 23:55:43 +09:00
330cb39daf Remove CentOS 7 from CI (#2579)
CentOS 7 is EOL and thus unsupported.  This reverts commit
44d5b5e1c9.
2024-10-29 18:23:36 +09:00
b87a8400e3 Use pass-by-value for peeloff (#2578)
This avoids copies when used with std::move.
2024-10-29 18:21:07 +09:00
3b226ed672 Make psemaphore similar to C++20 std::counting_semaphore (#2569) 2024-10-29 08:23:05 +09:00
07881195f2 Add missing mutex header (#2576)
Found via clang-tidy.
2024-10-29 00:11:28 +09:00
08a5d35f34 Add Ubuntu 24.10 to CI (#2575) 2024-10-29 00:10:44 +09:00
561ce1e206 Update ChangeLog and configure.ac for 1.95
Fixes #2496.
2024-10-25 10:42:53 -07:00
7cb46db945 Add missing string header (#2574)
Found via clang-tidy.
2024-10-25 16:13:57 +09:00
fe82477a6b Add missing utility header for std::move (#2572)
Found via clang-tidy.
2024-10-25 14:55:01 +09:00
b8e56a40b2 Fixed a bug in clearing the queue accumulated during USR1 processing 2024-10-25 14:47:15 +09:00
3ff93d7342 Simplify bucket_block_count initialization (#2571) 2024-10-25 08:37:48 +09:00
e43de21e43 Separate clang-tidy into its own CI task (#2567)
clang-tidy takes 4 minutes on my laptop compared to ALL_TESTS=1 which
takes 8 minutes.  Using a separate tasks avoids duplicating clang-tidy
and unnecessarily slowing CI run-time.
2024-10-24 08:25:30 +09:00
31061416bc Separate serialization and deserialization code (#2566)
This is clearer than a bool parameter.
2024-10-24 08:22:35 +09:00
a8af6cb3b4 Run clang-tidy against test files (#2568) 2024-10-23 20:46:01 +09:00
fe0a62118d Remove some unused parameters (#2565) 2024-10-22 20:34:22 +09:00
cc5271ef2b Enable clang-tidy narrowing conversions (#2564) 2024-10-22 19:55:10 +09:00
d35b5a8905 Add OpenSSL suppression for ThreadSanitizer (#2559) 2024-10-22 19:52:27 +09:00
64c96e89c5 Expand use of auto (#2563)
Found via clang-tidy.
2024-10-22 19:43:12 +09:00
9c4fcbd050 Use std::max instead of conditional (#2562)
Found via clang-tidy.
2024-10-22 19:22:39 +09:00
b34e2711a7 Fixed warnings on integer comparisons (#2558)
Follows on to 2d1409a672.
2024-10-22 18:53:37 +09:00
14f07626e0 Wrap EVP_MD_CTX in a std::unique_ptr (#2557) 2024-10-20 16:07:53 +09:00
8c5ac5c2d9 Remove more raw pointers (#2556)
Make destructor public so std::unique_ptr can call it.  Also restrict
singleton creation to satisfy cppcheck.
2024-10-20 16:06:05 +09:00
4b6e53223b Use std::shared_ptr to refer to FdEntity (#2541)
FdEntity may have multiple references due to ChangeEntityToTempPath.
This relies on the std::enable_shared_from_this helper to create a
std::shared_ptr from this.  Fixes #2532.
2024-10-20 14:56:29 +09:00
a505cebf9b Expand use of std::unique_ptr for FILE* (#2555) 2024-10-18 22:06:47 +09:00
141d74f187 Use auto for iterator variable types (#2554)
This touches a few other long type names.  Applied via clang-tidy
-fix.
2024-10-18 21:57:52 +09:00
4c5b7595b4 Add missing GUARDED_BY to fdcache_entity (#2549)
This requires a fake GetMutex for the lock checker to understand the
control flow.  Also remove unneeded locking comments that annotation
supersede.  Follows on to #2491.
2024-10-18 00:39:45 +09:00
e613ae55bb Replace curl_warnings_lock with std::atomic (#2550)
This is simpler and lighter-weight.
2024-10-18 00:36:36 +09:00
5594106351 Add miscellaneous locking annotations (#2551) 2024-10-18 00:34:57 +09:00
c5031a5a97 Simplify some method parameters (#2553)
Add const where possible and avoid unnecessary reference parameters.
2024-10-18 00:05:42 +09:00
473f9df65a FreeBSD compilation fixes
Closes #2517.
2024-10-16 13:46:12 -07:00
0c26014812 Fixed exclusive control of upload_id in PseudoFdInfo class 2024-10-16 02:46:48 +09:00
06a3822965 [Improvement #2490] Add GUARDED_BY to FdEntity and fix locking 2024-10-15 02:04:46 +09:00
2d1409a672 Fixed warnings on integer comparisons in openssl_auth.cpp 2024-10-15 02:00:20 +09:00
1d3ab76cc4 Ensure that test checks data length (#2546)
wc has an optimization that can use metadata when stdin is set to a
file.  Also fix up logging.
2024-10-14 18:31:37 +09:00
c00b5fd4bb Propoagate error state from insertV4Headers (#2547)
s3fs_sha256_hex_fd returns an empty string when calculating the hash
fails.
2024-10-14 10:28:19 +09:00
000273a8de Configure target for clang thread safety checking (#2493) 2024-10-14 10:19:03 +09:00
3ba8c2a139 Replace non-standard VLAs with std::array (#2544) 2024-10-13 12:03:56 +09:00
c0219b38d1 Return correct success value from NSS s3fs_md5 (#2543) 2024-10-13 11:58:54 +09:00
40f95272be Fix locking annotations and add one missing lock (#2542)
This allows clang's thread safety checks to pass.
2024-10-13 11:53:56 +09:00
15e2eae69a Address clang-tidy 19 warnings (#2540) 2024-10-13 10:09:47 +09:00
743c86e506 Fix issues discovered by Coverity (#2535) 2024-10-08 08:07:13 +09:00
4605cc2035 Fixed fake_diskfree option 2024-10-07 01:24:35 +09:00
a259981f16 Enable cppcoreguidelines-pro-type-const-cast (#2537)
This fixes dangerous uses of const_cast.
2024-10-06 18:40:48 +09:00
bbbb2d0908 Specify deleter function for regex_t unique_ptr (#2536) 2024-10-06 18:30:22 +09:00
e80de15cc6 Make FILE ownership clearer via unique_ptr (#2534) 2024-10-06 18:03:02 +09:00
b283ab291a Modified and bypassed test_multipart_mix on MacOS with nocopyapi 2024-09-29 13:58:46 +09:00
c24015ae17 Modified and bypassed some MacOS tests 2024-09-29 09:17:11 +09:00
df5364d758 Enable readability-implicit-bool-conversion (#2530)
This fixes one real error, one misreported EPERM, and some false
positives.  References #2529.
2024-09-28 15:28:50 +09:00
52c10cd45d Call Rename outside AutoFdEntity scope (#2528)
This avoids a use-after-free in the destructor.
2024-09-28 15:25:02 +09:00
e8f1e3473c Fixed miss-return code in S3fsCurl::RequestPerform 2024-09-28 13:25:37 +09:00
37cf324c52 Return non-zero exit code on Valgrind errors (#2527)
Previously this ignored use-after-frees and other errors.
2024-09-28 11:37:25 +09:00
5691071ac6 Log entire line when curldbg lacks a newline (#2526)
Previously -o curldbg=body would read uninitialized memory.
2024-09-28 11:35:49 +09:00
6faaff10ee Fixed hardlink test for macos 2024-09-27 00:52:07 +09:00
4796e982ab Fixed opensuse/leap:15 test 2024-09-27 00:51:51 +09:00
22869d99a5 Set errno to zero before calling sysconf (#2515)
FreeBSD returns -1 since it has no limits for _SC_GETPW_R_SIZE_MAX and
_SC_GETGR_R_SIZE_MAX but is not required to reset errno.  Also fix up
logging.  Fixes #2514.
2024-08-24 09:48:54 +09:00
7d2d4e8866 s3 signv4 support uri endpoints (#2510) 2024-08-17 13:46:13 +09:00
4fe2652c6c Fix Windows compilation (#2506)
* docs: Fix Windows compile instructions

Signed-off-by: Naoki Ikeguchi <me@s6n.jp>

* fix: Use fallocate stub on MSYS2

Signed-off-by: Naoki Ikeguchi <me@s6n.jp>

---------

Signed-off-by: Naoki Ikeguchi <me@s6n.jp>
2024-07-27 09:54:38 +09:00
fcb5aa77fb Fix minor issues when compiling with MSYS (#2505)
References #2503.
2024-07-27 09:43:16 +09:00
411e42384e Acquire lock before logging (#2502)
This is not safe -- another caller could modify a std::string field
while logging which could read an invalid pointer.  References #2490.
2024-07-21 16:14:22 +09:00
1c2f61e2a5 Remove unneeded lock utility functions (#2500)
std::mutex RAII removes the need for these.

Co-authored-by: Takeshi Nakatani <ggtakec@gmail.com>
2024-07-15 15:32:39 +09:00
23efccbe39 Disable thread safety analysis on conditional locks (#2498)
Clang does not support this:

https://clang.llvm.org/docs/ThreadSafetyAnalysis.html#conditional-locks

Co-authored-by: Takeshi Nakatani <ggtakec@gmail.com>
2024-07-15 15:17:47 +09:00
77ffe7d634 Wrap CURL* in a std::unique_ptr (#2495)
This is safer and clarifies the ownership of pointers.

Co-authored-by: Takeshi Nakatani <ggtakec@gmail.com>
2024-07-15 15:15:03 +09:00
60b871e0ae Simplify has_mp_stat (#2499)
This is unnecessary since we moved from pthread_mutex_t to
std::atomic.
2024-07-15 15:04:28 +09:00
44d5b5e1c9 Continued Github Actions(CI) execution after CentOS 7 EOL 2024-07-13 10:30:27 +05:30
03651a30ea Add infrastructure for clang static lock checking (#2492)
Co-authored-by: Takeshi Nakatani <ggtakec@gmail.com>
2024-07-13 09:48:43 +09:00
db80fa2eb0 Upgrade CI to Alpine 3.20 2024-07-11 23:14:07 +05:30
6f90c6918f Fix incorrect locking annotations (#2494)
Co-authored-by: Takeshi Nakatani <ggtakec@gmail.com>
2024-07-11 23:13:44 +09:00
437bf7ec95 Convert pthread_t to C++11 std::thread (#2481)
This has better cross-platform support and stronger type-safety.
2024-07-11 22:37:25 +09:00
50d5a73f84 Simplify curl progress tracking (#2486)
Use a struct with named fields instead of a pair for clarity and use a
single map to store the structs for efficiency.
2024-07-06 16:35:25 +09:00
ec183d0d9a Dropped Github Actions(CI) for CentOS 7 and Debian 10(Buster) 2024-07-01 23:46:18 +05:30
ae28a110ab Remove unused function (#2484)
Also clean up some function prototypes.

Co-authored-by: Takeshi Nakatani <ggtakec@gmail.com>
2024-07-01 23:30:32 +09:00
a6637b29e6 Opt in to all clang-tidy checks by default (#2477)
Opt out of the noisy checks.  Disable clang-tidy on Debian bullseye
and buster and Ubuntu 20.04 due to segfaults.
2024-07-01 22:29:34 +09:00
1a50b9a04a Fixed a deadlock in the FdManager::ChangeEntityToTempPath method call 2024-06-30 20:29:01 +05:30
585f137cf0 Remove unused headers found by clang-tidy (#2480)
Found via misc-include-cleaner but this requires more work.
2024-06-25 23:32:46 +09:00
1449905fe5 Make deleted constructors and operators public (#2479)
Deleting them better conveys the intent.
2024-06-24 08:26:24 +09:00
622dc0a815 Convert pthread_mutex to std::mutex (#2476)
This simplifies resource management and improve Windows compatibility.
2024-06-24 00:48:01 +09:00
86b353511a Replace memset with C++11 value initialization (#2471)
This generates the same code but is safer due to using an implicit
length and allowing member initialization.
2024-06-24 00:24:49 +09:00
a3a0ae523f Changed the display format of the Git commit hash in the version display 2024-06-23 16:01:33 +05:30
fa807a56fb Fix typos (#2473) 2024-06-23 15:33:46 +09:00
254d717a4a Address clang-tidy 19 warnings (#2474) 2024-06-23 12:21:51 +09:00
86e6bdaf4d Apply clang-tidy to headers (#2470) 2024-06-23 11:49:59 +09:00
2841601ad5 Remove uses of AutoLock::ALREADY_LOCKED (#2466)
Instead annotate the methods with REQUIRES so that the caller knows if
they should lock.  For public interfaces, introduce HasLock wrappers.
This simplifies control flow, allows migration to std::mutex, and
eventually will enable use of static lock checking.
2024-06-23 11:24:51 +09:00
39c2d8b2a7 Improve CI workflow 2024-06-14 16:22:12 +09:00
683452a9be Remove unnecessary copy constructors and operator= (#2468) 2024-06-10 23:37:53 +09:00
ebae5a302f Prefer std::string::clear where possible (#2467)
This is somewhat more clear and is declared noexcept.
2024-06-10 23:36:49 +09:00
ba7b2ef9f0 Return boolean as bool not int (#2465) 2024-06-04 22:38:30 +09:00
f3946a2310 Keep cache path parameters as std::string (#2464)
While some of these originate as char *, eventually they convert to
std::string in the std::map lookup.
2024-06-04 22:37:48 +09:00
a4f694c345 Pass const std::string by reference (#2461)
This is more idiomatic than by pointer.
2024-05-28 09:17:45 +09:00
2c532e8b79 Fixed error reports of failure in cppcheck 2.14.0 2024-05-28 07:29:03 +09:00
5c1932f702 Upgrade CI to Ubuntu 24.04 LTS (#2456) 2024-05-12 11:12:25 +09:00
ccdcccd44c Fix DeadLock in FdManager::ChangeEntityToTempPath (#2455)
commit e3b50ad introduce smart pointer to manage FdEntity

But in ChangeEntityToTempPath, we should not destroy the entity.

We should move the entry to the temp ky

Signed-off-by: liubingrun <liubr1@chinatelecom.cn>
2024-05-11 11:29:40 +09:00
3864f58c22 Upgrade CI to Fedora 40 (#2451) 2024-05-11 09:25:05 +09:00
c36827d1de Fixed README.md for Github Action Badge URL (#2449) 2024-04-28 20:10:53 +09:00
e2cc36a37f Updated COMPILATION.md about compilation on linux (#2445) 2024-04-28 14:31:01 +09:00
cf6102f91b Changed due to s3fs-fuse logo change (#2448) 2024-04-28 14:28:24 +09:00
dd6815b90f retry request on HTTP 429 error 2024-04-14 12:09:26 +09:00
95026804e9 Support SSL client cert and added ssl_client_cert option 2024-04-14 10:21:48 +09:00
9ab5a2ea73 Fixed configure error for GHA:sanitize_thread 2024-03-19 21:37:19 +09:00
a5cdd05c25 Added ipresolve option 2024-03-13 22:29:17 +09:00
31676f6201 Convert thpoolman_param to value (#2430)
This simplifies memory management.
2024-03-13 21:27:12 +09:00
c97f7a2a13 Address clang-tidy 18 warnings (#2428) 2024-03-07 01:04:22 +09:00
be54c34ecb Remove unneeded XML macros (#2427) 2024-03-07 00:45:34 +09:00
79597c7960 Upgrade CI to Alpine 3.19 (#2429) 2024-03-07 00:23:00 +09:00
70a30d6e26 Update ChangeLog and configure.ac for 1.94
Fixes #2420.
2024-02-25 13:08:43 +09:00
b97fd470a5 Abort for SSE-KMS encryption type and not SSL/TLS specified 2024-02-23 13:11:56 +09:00
4d7fd60305 Call abort instead of exit in tests (#2416)
This can give useful core dumps.
2024-02-23 12:28:29 +09:00
da38dc73ad Gentoo + libxml2-2.12 requires inclusion of parser.h 2024-02-20 08:28:42 +09:00
e89adf6633 Fixed a bug that mounting with ksmid specified to fail 2024-02-18 21:18:50 +09:00
fa2bcfc60d Fixed a bug in multi head request parameter 2024-02-12 17:37:03 +09:00
ed1d431a1f Improved to output error details when bucket check fails 2024-02-12 17:36:47 +09:00
67442cf054 Changed the level of messages by the get_base_exp function 2024-02-12 17:35:45 +09:00
a7186b6072 Updated actions/checkout from v3 to v4 2024-02-07 21:29:42 +09:00
517574c40c Fixed a bug in fdatasync(fsync) 2024-02-06 14:11:37 +09:00
5e6f21a9ff fix: ListBucket edge cases (#2399) 2024-02-03 13:24:40 +09:00
54aa278df0 Fixed errors reported by cppcheck 2.13.0 (#2400) 2024-01-25 00:46:45 +09:00
2f9fb74a42 Corrected list_bucket to search in stat cache during creating new file (#2376) 2024-01-24 22:10:14 +09:00
b82632547c Replace miscellaneous pointers with unique_ptr (#2388) 2023-12-23 13:06:41 +09:00
e3b50ad3e1 Convert FdEntity to std::unique_ptr (#2383) 2023-12-07 23:56:35 +09:00
b139507ae6 Simplify locking with C++11 atomics (#2382) 2023-11-27 01:12:49 +09:00
feb0845103 Use JDK 21 for Ubuntu 23.10 (#2380) 2023-11-27 00:55:35 +09:00
f041812939 Revert "Call C++11 get_time and put_time (#2375)" (#2381)
This reverts commit 10a72bfd0f.  These
commit is incompatible with older CentOS 7 libstdc++.
2023-11-27 00:51:17 +09:00
2b57e74330 Use std::unique_ptr in threadpoolman (#2374) 2023-11-26 01:49:17 +09:00
b671fa7a9c Pass std::unique_ptr by value (#2373)
This ensures that the parameter is moved.
2023-11-26 01:48:47 +09:00
691669749e Remove obsolete C++11 #ifdef (#2377) 2023-11-21 00:37:42 +09:00
10a72bfd0f Call C++11 get_time and put_time (#2375)
This removes workarounds and fixed-length buffers.
2023-11-20 18:45:27 +09:00
43f81b76af Enable clang-tidy CERT warnings (#2371) 2023-11-19 10:00:42 +09:00
68bbfee8ea Address clang-tidy modernize-deprecated-headers (#2370) 2023-11-19 10:00:16 +09:00
ec8caf64b8 Reverted the macos CI process(using macos-fuse-t) 2023-11-17 21:08:34 +09:00
bcacca6599 s3fs: make dir size not zero
Directory has size 0, which looks weired and may confuse users. So fake
dir size as 4k.

Signed-off-by: Eryu Guan <eguan@linux.alibaba.com>
2023-11-17 17:55:57 +09:00
4fdd2456d4 Fixed a script of not functioning environment in Github Actions 2023-11-15 23:17:26 +09:00
3f6e8a8707 Fixed indent in integration-test-main.sh 2023-11-15 23:15:40 +09:00
4845831f93 Convert some const to constexpr (#2342)
This guarantees that the function or value will resolve at compile-time.
2023-11-14 22:15:17 +09:00
919575f312 Upgrade CI to Fedora 39 (#2365) 2023-11-12 16:01:09 +09:00
0cd73e406d Address clang-tidy 17 warnings (#2362) 2023-11-12 11:48:08 +09:00
807ec1f6f7 Upgrade CI to Alpine 3.18 (#2332)
References #2328.
2023-11-12 11:08:44 +09:00
e2ac9b45e8 Re-improved updating of temporary stat cache when new file 2023-11-11 07:45:32 +09:00
b15ed13807 Force disk free space recovery in test(for only macos) 2023-11-10 15:51:22 +09:00
f9d3941d9d Fixed a bug in the re-upload part of Streamupload 2023-11-10 10:41:26 +09:00
34c379babb Improved updating of temporary stat cache while creating a file 2023-11-10 10:23:15 +09:00
7b5111c955 Suppress some message levels on macos 2023-11-09 14:16:43 +09:00
a3964b3fcd Upgrade CI to Ubuntu 23.10 (#2355) 2023-10-22 22:18:29 +09:00
3856637cd2 s3fs: add option free_space_ratio to control cache size (#2351)
* Try to cleanup cache directory when initing without enough disk space

Also optimize log messages to print detailed errors to the user.

Signed-off-by: Qinqi Qu <quqinqi@linux.alibaba.com>

* s3fs: add option free_space_ratio to control cache size

Since the ensure_diskfree option is not convenient enough, we have added
a new option "-o free_space_ratio" to control the space used by the s3fs
cache based on the current disk size.

The value of this option can be between 0 and 100. It will control the
size of the cache according to this ratio to ensure that the idle ratio
of the disk is greater than this value.

For example, when the value is 10 and the disk space is 50GB, it will
ensure that the disk will reserve at least 50GB * 10% = 5GB of remaining
space.

Signed-off-by: Qinqi Qu <quqinqi@linux.alibaba.com>

---------

Signed-off-by: Qinqi Qu <quqinqi@linux.alibaba.com>
2023-10-20 18:11:47 +09:00
2871975d1e Set SSE headers when checking bucket 2023-10-18 21:45:47 +09:00
d5dd17644d Add a helper script to compile all targets (#2337)
This is useful to compile different SSL libraries and 32-bit targets.
2023-10-15 11:54:52 +09:00
5e5b4f0a49 Fixed ETag parsing at completing the Multipart upload part 2023-10-13 11:13:52 +09:00
e5b15bed7d Pass by value to trim functions (#2345)
These already force a copy so passing by value has the same
performance but is simpler.  But this allows the compiler to perform
copy elision on temporaries and the caller to explicitly std::move in
others.
2023-10-12 22:21:33 +09:00
2e4a6928c3 Changed argument name in ParallelMultipartUploadAll 2023-10-09 13:17:25 +09:00
1aa77f6cda s3fs_cred: print detailed error message when stat file fails
Signed-off-by: Qinqi Qu <quqinqi@linux.alibaba.com>
2023-10-09 13:11:47 +09:00
d0c4b5c763 Fixed a bug in exclusive control of pagelist in FdEntity class 2023-09-26 21:26:17 +09:00
361e10d09c Add scope_guard for ad-hoc resource management (#2313)
References #2261.  Suggested by:
https://stackoverflow.com/questions/10270328/the-simplest-and-neatest-c11-scopeguard
2023-09-26 07:52:55 +09:00
95cfbe30ed Add error checking to test_concurrent_writes (#2299)
This reveals a situation where s3fs triggers an unexpected
EntityTooSmall error.
2023-09-26 07:32:02 +09:00
87b8bafaea Address unknown pragma warning with GCC (#2324) 2023-09-26 01:16:14 +09:00
1a703e623a Remove volatile qualifiers deprecated in C++23 (#2323)
These are protected by upload_list_lock.  Addresses warnings of the
form:

warning: ‘++’ expression of ‘volatile’-qualified type is deprecated
2023-09-26 00:15:05 +09:00
1ebefca029 Reorder $CXXFLAGS to the end (#2322)
This allows overriding flags like -std=c++11.
2023-09-26 00:05:54 +09:00
ffff26e165 Add stat helper for user and group (#2320) 2023-09-26 00:04:24 +09:00
61df7bf42c Use std::unique_ptr for fclose (#2318)
References #2261.
2023-09-25 23:55:11 +09:00
c5fb42ff10 Use std::unique_ptr in libxml functions (#2317)
References #2261.
2023-09-25 23:46:52 +09:00
cbc33cd7ae Fixed a bug upload boundary calculation in StreamUpload 2023-09-25 09:28:37 +09:00
645c10a3c3 Fixed test_not_existed_dir_obj test condition 2023-09-25 08:16:32 +09:00
54293a66b3 Simplify the determination of the --cached option of the stat 2023-09-25 08:08:58 +09:00
01b3caa38c Fixed errors of cppcheck 2.12.0 2023-09-24 19:55:02 +09:00
64642e1d1b Do not cache stat attributes (#2319)
This is a workaround for CI failures.
2023-09-24 18:32:07 +09:00
546cdd0d91 Improve docs on environment variables 2023-09-21 12:40:46 +09:00
a83f4a48d0 Add extra logging to debug test (#2316) 2023-09-15 21:50:01 +09:00
99d3e68d59 Revert ls change (#2315)
echo does not split the words on newlines.
2023-09-15 21:48:04 +09:00
01189e99fc Store mvnode in vector instead of manual linked list (#2312)
This simplifies code and avoids manual memory management.  References #2261.
2023-09-13 22:32:15 +09:00
f493cb5846 Remove unnecessary uses of ls (#2311)
Other call sites need the call to readdir/getdents64.
2023-09-13 22:27:12 +09:00
e9814b4a4d Add Debian bookworm to CI 2023-09-11 00:59:23 +09:00
3b12aaf2ab Do not escape percent (#2310)
This addresses warnings of the form:

grep: warning: stray \ before %
2023-09-10 12:51:36 +09:00
7e20278489 Address some Shellcheck SC2012 warnings (#2306) 2023-09-10 12:50:18 +09:00
3d73d5a687 Delete unneeded constructors and assignment operators (#2309) 2023-09-06 23:52:10 +09:00
fa3a472c6b Remove several calls to free (#2308) 2023-09-06 23:50:33 +09:00
5f38301861 Emit unexpected file names in failed test_list (#2307) 2023-09-06 23:47:12 +09:00
4d5632912a Initialize variable before use (#2302)
clang-analyzer found a path where this could be used without
initialization.
2023-09-06 23:32:49 +09:00
a74034a012 Fixed a bug with setting the statvfs value 2023-09-05 09:03:11 -07:00
3f64c72c24 Explicitly grep for ps args (#2301) 2023-09-03 22:03:45 +09:00
68c45ce791 s3fs: print unmounting hint when the mount point is stale (#2295)
When the error code returned by the stat information of the mount point
is ENOTCONN, print unmount command hint for user to fix.

Signed-off-by: Qinqi Qu <quqinqi@linux.alibaba.com>
2023-09-03 10:50:09 +09:00
e8cb6d6d34 Abort after failed MPU (#2298)
This reclaims storage after a failed MPU which caused OutOfMemory
issues in #2291.
2023-08-29 23:29:16 +09:00
a2f2f72aaf Enable Valgrind in CI (#2297)
Using HTTP instead of HTTPS and
82107f4b6c improve test run-time so that
this is now feasible.
2023-08-29 23:11:26 +09:00
7bb9609827 Return errors from AutoFdEntity::Open (#2296)
Found via pjdfstest which creates a PATH_MAX path that should return
NAMETOOLONG.
2023-08-29 22:57:30 +09:00
82107f4b6c Skip is_uid_include_group when GID available (#2292)
This can avoid an expensive computation which is 20% of test runtime.
2023-08-27 15:24:33 +09:00
ee49ca4abf s3fs: print fuse context in s3fs fuse operations (#2274)
Print fuse context like pid in fuse operations, so we know which process
is triggering this operation.

Signed-off-by: Eryu Guan <eguan@linux.alibaba.com>
2023-08-27 14:00:57 +09:00
48548f0896 Remove unused functions (#2289) 2023-08-22 23:17:43 +09:00
981e97ee76 Use default move constructor (#2288)
This is identical to the explicit one.
2023-08-22 23:14:09 +09:00
a568aa70fd Replace uses of emplace with operator=(&&) (#2287)
emplace does not overwrite the value if the key already exists.  C++17 has
insert_or_assign but C++11 only has operator= which invokes the default
constructor.  Follows on to 6781ef5bd1.
2023-08-22 23:12:12 +09:00
218adcb29b Fixed errors in cache.cpp from cppcheck 2.11.1 (#2286) 2023-08-20 19:00:20 +09:00
6c55bcfdd8 Own values in add_header (#2285)
Also fix up indentation.
2023-08-20 18:59:18 +09:00
8d04ee3e01 Own values in stat_cache and symlink_cache (#2284)
This removes an unnecessary use of unique_ptr.
2023-08-20 12:10:47 +09:00
6781ef5bd1 Reverted to direct array access instead of std::map emplace 2023-08-20 09:44:38 +09:00
7e94b64ae7 Use unique_ptr in SSL functions (#2282)
References #2261.
2023-08-19 23:29:00 +09:00
64a142723a Document environment variable configuration (#2281) 2023-08-19 23:23:05 +09:00
50f6c38c84 Replace xattr_value with std::string (#2280) 2023-08-19 11:12:43 +09:00
9fb4c32c6a Test filenames longer than POSIX maximum (#2277) 2023-08-18 08:58:44 +09:00
280ed5d706 Additional fix for #2276(Convert BodyData to std::string) (#2278) 2023-08-18 00:35:50 +09:00
2518ff3568 Convert BodyData to std::string (#2276)
This is simpler and avoids some copies.
2023-08-17 22:49:41 +09:00
c65ce8a42c Add clang-tidy to CI (#2270) 2023-08-17 22:42:11 +09:00
e5986d0034 Run all tests with sanitizers (#2275) 2023-08-17 22:27:06 +09:00
b2bb12fd2c Remove unneeded explicit std::string constructors (#2273)
std::string(const char*) implicitly constructs these.  The remaining call sites
requires string literals from C++14.
2023-08-17 22:12:28 +09:00
7f30353fb9 Return std::unique_ptr from S3fsCurl callbacks (#2272)
References #2261.
2023-08-17 22:08:56 +09:00
235bccced5 Added make check for src directory for Linux OS 2023-08-16 08:07:02 +09:00
67e6b9e495 Simplify xattr_value with owned values (#2262)
References #2261.
2023-08-15 22:54:46 +09:00
ea42911530 Build s3fs in parallel like in CI (#2267) 2023-08-15 22:37:39 +09:00
6823c5a7ec Enable clang-tidy cppcoreguidelines (#2269) 2023-08-15 22:12:33 +09:00
d1272d296a Tighten up CLI argument handling (#2268)
This ensures that each option is only handled once.
2023-08-15 21:45:38 +09:00
d2a571a868 Set exit code for Valgrind (#2265)
Otherwise errors can be ignored for successful tests with memory
errors.
2023-08-15 21:33:34 +09:00
d120e54284 Improve illegal bucket name error message (#2263)
This may help users debug situations like:

https://stackoverflow.com/questions/76359564/why-does-mounting-s3fs-bucket-on-centos-7-using-fstab-fail-but-mount-a-works
2023-08-15 21:31:05 +09:00
3a6af38582 Tighten up Content-Type checking (#2258) 2023-08-15 21:23:59 +09:00
e157d811cb Use std::string::compare and operator== where possible (#2256) 2023-08-15 21:22:36 +09:00
56a4e67009 Replace more raw pointers with std::unique_ptr (#2255) 2023-08-14 00:03:10 +09:00
5b93765802 Fixed a warning for compiling C/C++ codes 2023-08-13 20:49:39 +09:00
acea1d33f9 Fixed string test for s3fs_base64 2023-08-13 20:48:38 +09:00
528a61718d Convert manual memory allocations to std::unique_ptr (#2253) 2023-08-11 23:26:07 +09:00
c5a75a1fb2 Delete copy constructors and assignment operators (#2257)
One of these was buggy and others had the wrong parameters and return
types.
2023-08-11 13:12:03 +09:00
3790a0f8b4 Calculate MD5 without using a temporary file (#2252)
This mirrors the SHA256 code.
2023-08-07 00:17:15 +09:00
779afe5d62 Make help more consistent (#2251) 2023-08-06 22:25:10 +09:00
26b5658d70 Wrap ps3fscred with std::unique_ptr (#2250)
This removes many manual memory deallocations.
2023-08-06 22:23:25 +09:00
c568a69452 Return std::string from base64 encoding function (#2248)
This is avoids manual memory allocations.
2023-08-06 22:22:02 +09:00
13ad53eef7 Convert most std::list to std::vector (#2247)
This tends to be more efficient due to fewer allocations.  Also fix std::sort
comparator which should be strictly less than.
2023-08-05 10:05:32 +09:00
b14758baff Fix junk_data for 32-bit platforms (#2245)
Previously this had a mismatch between size_t and unsigned long long.
2023-08-05 09:37:18 +09:00
b5c3fc0a08 Convert fixed-size allocations to C++11 std::array (#2242)
This is safer and more efficient.
2023-08-05 09:36:22 +09:00
b29f8d0f2b Use C++ enum class for most enums (#2241)
This promotes type-safety.
2023-07-30 22:53:17 +09:00
5699875e30 Use C++11 emplace where possible (#2240)
This is more concise and sometimes more efficient.
2023-07-30 22:51:20 +09:00
3081e419e1 Simplify direct shellcheck download with jq (#2239) 2023-07-29 09:22:55 +09:00
a7b38a6940 Address stray warnings (#2237) 2023-07-29 09:19:18 +09:00
1f04165a33 Convert most str callers to C++11 std::to_string (#2238)
Remaining ones handle timespec.
2023-07-28 18:21:55 +09:00
36db898d01 Use C++11 std::map::erase return value (#2236) 2023-07-27 23:34:43 +09:00
38a1ff42e5 Convert test binaries to C++ (#2235)
This ensures that they are compiled with a consistent compiler and set of flags
as the rest of s3fs.
2023-07-27 23:15:19 +09:00
a4a2841c05 Use C++11 nullptr instead of 0 or NULL (#2234)
This improves type-safety.
2023-07-27 21:56:58 +09:00
0ece204393 Fix -Wshorten-64-to-32 warnings 2023-07-27 12:23:26 +09:00
6344d74ae3 Replace some raw pointers with std::unique_ptr (#2195)
This simplifies code paths and makes memory leaks less likely.  It
also makes memory ownership more explicit by requiring std::move.
This commit requires C++11.  References #2179.
2023-07-27 09:12:28 +09:00
faec0d9d15 Refixed for cppcheck 2.1x 2023-07-26 07:55:33 +09:00
e14a2eb94b Add AWS CLI config for use_sse=custom (#2230) 2023-07-25 23:31:20 +09:00
cb3dc28e6e Supported cppcheck 2.10(and changed std from c++03 to c++11 for RHEL7) 2023-07-25 08:08:06 +09:00
38dc65180b Fixed checking cppcheck version in ci.yml 2023-07-24 11:07:31 +09:00
2405706643 Insert SSE headers when appropriate (#2228)
References #2218.  References #2227.
2023-07-23 16:17:34 +09:00
5371cd1468 Update ChangeLog and configure.ac for 1.93 (#2225)
Fixes #2213.
2023-07-19 22:31:43 +09:00
7978395083 Use smart pointer to manage pcfstat object
Previously pcfstat points to a raw pointer, and it may be leaked if
function returned before deleting it.

So use smart pointer to automatically release the object.

Note that currently s3fs only uses c++03, so we use auto_ptr here, not
unique_ptr, which requires c++11.

Fixes: 6ca5a24a7f ("Fix two inconsistency issues between stat cache and cache file (#2152)")
Signed-off-by: Eryu Guan <eguan@linux.alibaba.com>
2023-07-19 20:15:55 +09:00
d0a944fcaa Fixed data race about fuse_fill_dir_t function and data pointer 2023-07-14 22:32:12 +09:00
537384e9b5 Guard filler calls with filled check (#2215)
Follows on to e650d8c55c.
2023-07-13 22:46:19 +09:00
e650d8c55c Explicitly handle CommonPrefixes with nocompat_dir (#2212)
Previously the test missed listing implicit directories and another
test was incorrect.  This fixes a regression from 1.91.
2023-07-13 21:15:34 +09:00
9663215bb4 Fixed data race at OPENSSL_sk_dup/free in libcurl 2023-07-12 22:51:57 +09:00
b2537052ef Fixed data race in threads found thread sanitizer 2023-07-09 20:53:27 +09:00
2e51908bec Check FdEntity::Open() status correctly
FdEntity::Open() returns -errno on error, but FdManager::Open() only
checks if its ret is -1. This may lead to use '-errno' as pseudo fd
in next read or write, which would fail due to '-errno' is not in
fent map.

Signed-off-by: Eryu Guan <eguan@linux.alibaba.com>
2023-07-05 08:50:12 +09:00
a8edbd8622 fix streamuplod not working (#2204)
fuse_main will do fork to daemonize. if ThreadPool is created before
this, worker thread will not be placed in child process.

Move ThreadPool Init to s3fs_init and destory to s3fs_destory.

Signed-off-by: liubingrun <liubr1@chinatelecom.cn>
2023-07-02 10:56:59 +09:00
06d0852e74 Use JDK 17 for Ubuntu CI (#2200)
Also remove stale 18.04 configuration.
2023-06-26 22:07:04 +09:00
03066ea29a Fix extended attribute support when using FUSE-T (#2201)
* Add support for FUSE-T on macos

Signed-off-by: Alex Fishman <alex@fuse-t.org>
Signed-off-by: alex <alex@alex-NUC10.lan>

* Ignore value pointer when size is zero on setattrx

Signed-off-by: Alex Fishman <alex@fuse-t.org>

---------

Signed-off-by: Alex Fishman <alex@fuse-t.org>
Signed-off-by: alex <alex@alex-NUC10.lan>
2023-06-26 22:05:37 +09:00
e66c9a82a2 Add sanitize_thread to CI (#2199) 2023-06-25 23:13:49 +09:00
e86e6cf24f Add Ubuntu 23.04 and remove 18.04
18.04 is EOL:

https://ubuntu.com/blog/ubuntu-18-04-eol-for-devices

This removes a FUSE 3 blocker.  References #1159.
2023-06-25 22:53:59 +09:00
7e8238abc0 Upgrade to JDK 17 (#2196)
Newer distros package this but some older ones do not.  Also remove
stale Ubuntu 16.04 configuration.
2023-06-25 18:05:38 +09:00
6448c8f1a8 Protect FdEntity::physical_fd with fdent_lock (#2194)
* Protect FdEntity::physical_fd with fdent_lock
Found via ThreadSanitizer.
2023-06-25 16:43:15 +09:00
3b6688253f Address cppcheck 2.10 warnings (#2163)
Disable newer cppcheck until we can diagnose this further.
References #2162.
2023-06-25 16:04:16 +09:00
45e7cd085a Add support for FUSE-T on macos
Signed-off-by: Alex Fishman <alex@fuse-t.org>
Signed-off-by: alex <alex@alex-NUC10.lan>
2023-06-24 22:26:42 +09:00
7c9cf84316 Added several memory checks to CI 2023-06-11 10:23:08 -07:00
580775b47c Removed unnecessary debug output 2023-06-07 20:48:50 -07:00
eab26a1e01 Fixed test setting for macOS 2023-06-07 20:48:34 -07:00
1910856c6c Remove wait and check loop from mk_test_file (#2175)
This appears to be some kind of eventual consistency check.  This
should have no effect given S3Proxy and recent AWS strong consistency.
Also it is likely ineffective given the other test object creation
operations.
2023-06-07 23:24:31 +09:00
4b3e715291 Always return nanoseconds from get_time helpers (#2174)
This makes Linux and macOS more consistent.
2023-05-30 18:52:55 +09:00
6ca5a24a7f Fix two inconsistency issues between stat cache and cache file (#2152)
* Fix inconsistency between stat cache file and cache file

We unlock stat cache file too early in FdEntity::Open(), and would
truncate cache file and update stat cache file, so there's a window that
stat cache doesn't reflect cache file status.

Suggested-by: Takeshi Nakatani <ggtakec@gmail.com>
Signed-off-by: Eryu Guan <eguan@linux.alibaba.com>

* Mark pagelist as unloaded if cache file has been truncated

If cache file size doesn't match object size, the cache file might be
corrupted, so invalidate it and save new cache stat file.

Suggested-by: Takeshi Nakatani <ggtakec@gmail.com>
Signed-off-by: Eryu Guan <eguan@linux.alibaba.com>

---------

Signed-off-by: Eryu Guan <eguan@linux.alibaba.com>
2023-05-30 18:39:50 +09:00
0d6b02090e Revert "Update curl.cpp: reduce memory cache use (#2157)" (#2170)
This reverts commit 5b487f651a.
2023-05-27 20:33:43 +09:00
5b487f651a Update curl.cpp: reduce memory cache use (#2157)
flush the file and clean the page cache when filepart download done
2023-05-27 19:15:47 +09:00
e7a364d610 Specify _FORTIFY_SOURCE=3 (#2168)
This can find more kinds of buffer overflows:

https://developers.redhat.com/articles/2022/09/17/gccs-new-fortification-level
2023-05-27 17:20:29 +09:00
161be3ff33 Update ChangeLog and configure.ac for 1.92 (#2166) 2023-05-22 08:25:50 +09:00
1fc0e52dc3 Fixed mount point stat flag to be thread safe 2023-05-21 13:46:06 +09:00
7bf4ca1837 Add Fedora 38 and remove 36 from CI (#2160) 2023-05-14 13:41:12 +09:00
59c3b26655 Fix clang-tidy 16 nits (#2158) 2023-05-14 01:59:26 +09:00
8296fe32cb Directly and simplify requests in mount point checks (#2155) 2023-05-14 01:29:24 +09:00
4a15699669 Disabled to run github action for macos (#2154) 2023-05-08 20:29:20 +09:00
24b990d899 Disabled to run github action for macos (#2154) 2023-05-08 20:28:41 +09:00
ca9a257eec Allow mount points without directory objects by compat_dir (#2153) 2023-05-07 09:15:27 +09:00
6d4bb59865 Corresponded to upload in case of calling release without flush (#2150) 2023-04-23 22:59:04 +09:00
9b75abfbe6 New option: bucket_size (#2148)
* Added bucket_size option
2023-04-23 14:04:38 +09:00
c4f95f14cb Fixed a bug about attributes of mount point (#2147) 2023-04-15 14:34:39 +09:00
9c74014443 Fixed a bug in handling file names containing CR(0x1D) (#2136) 2023-03-26 13:19:16 +09:00
a25cb9e07a Fixed a bug when reading a reduced file without flushing (#2133) 2023-03-26 11:45:21 +09:00
2cd7c94653 Fixed configure.ac by autoupdate (#2134) 2023-03-21 15:10:55 +09:00
9648eba5bb Changed to rename cache files when renaming large files (#2135) 2023-03-21 14:15:34 +09:00
18495c44aa Added cache clearing on upload error (#2127) 2023-03-13 21:22:13 +09:00
4f22354aae Fix an error to calculate no data page bytes (#2122)
Co-authored-by: Takeshi Nakatani <ggtakec@gmail.com>
2023-03-11 17:23:56 +09:00
9d00b8d4a8 Fixed segmentation fault caused by file write failure (#2123) 2023-03-11 16:45:56 +09:00
aeacd0a7d3 Updated README.md(feat #2109) (#2115) 2023-03-05 15:03:48 +09:00
526700f2de Updated files for support ALPINE v3.17 (#2116) 2023-03-05 13:30:59 +09:00
a25a9450a6 Fixed to fail when the mount point directory is not existed (#2114) 2023-03-05 13:03:48 +09:00
f8a825e9b9 multipart upload id is converted by url encode (#2097) 2023-02-18 11:40:25 +09:00
dbddd762a9 Fixed token update process using ext-cred library (#2101) 2023-02-18 09:49:05 +09:00
e715b77307 Added the function to update mtime/ctime of the parent directory (#2016) 2023-02-12 17:59:40 +09:00
d1388ff446 Added proxy and proxy_cred_file option 2023-02-08 21:53:34 +09:00
38e8a830c9 Fixed a deadlock bug when specifying iam role(IAMv2) 2023-01-31 20:53:39 +09:00
7605c2e8fb Updated help contents and man pages for streamupload and etc 2023-01-31 20:53:20 +09:00
16bc44948e Retry BucketCheck containing directory paths 2023-01-09 21:18:47 +09:00
e4f85c1e08 Fixed renaming bug with SSE 2023-01-09 21:17:48 +09:00
222110e153 Fixed a bug about multipart upload with SSE 2023-01-07 09:12:55 +05:30
a40004f9cc Fixed a conflict between curl and curl-minimal on RockyLinux 9 (#2086) 2023-01-04 22:18:28 +09:00
0ba49518e9 Make some methods and parameters const (#2078)
This requires making some locks mutable.
2023-01-04 20:23:39 +09:00
14eb1a7fd8 Update readme, mac instructions, on M1 2022-12-07 07:46:17 +09:00
23a8124c51 Compatible with OpenSSL 3.0 2022-11-27 21:46:08 +09:00
f5af9dc4e2 Updated issue and pull request github templates 2022-11-23 21:58:21 +09:00
d8e4e34b74 Fixed a warning by compiling on fedora 37 2022-11-23 21:57:31 +09:00
d98fdf4b2e Fix man page inaccuracies 2022-11-22 22:47:11 +09:00
4e5f17e907 Fixed test_posix_acl test 2022-11-22 22:31:02 +09:00
38cdaeb191 Added Fedora:37 and RockyLinux:9 to Github Actions target OS 2022-11-22 22:30:30 +09:00
956eb77369 Updates for clang-tidy 15 (#2058) 2022-11-21 23:29:35 +09:00
465986e397 Fixed a bug when end of path for mount point is multi slash (#2057) 2022-11-19 15:07:27 +09:00
23a5583a7f Updated actions/checkout for gha from v2 to v3 (#2053) 2022-11-05 15:08:42 +09:00
aec7efc3af Updated comments in curl.cpp (related to #1827) (#2052) 2022-11-05 11:45:28 +09:00
30353f1a83 Remove unnecessary calls to dup (#1827)
These functions already use pread and keep track of an explicit offset
for the SHA-256 calculations.
2022-11-05 10:24:41 +09:00
6f4bf55d5e fix: handle file names with ':' in them 2022-11-01 06:19:47 -07:00
2e77920943 Added support for xattr as POSIX ACL (#2039) 2022-10-22 21:48:02 +09:00
4a813aec42 Support the object under no directory object path by compat_dir (#2023) 2022-10-22 15:12:00 +09:00
4304ec63bb Added stat information to the mount point (#1964) 2022-10-22 11:46:13 +09:00
6e89e69bba Enabled to load shared library for Credential and Token (#1927) 2022-10-22 10:42:07 +09:00
9a4282208e Improved fdcache_page performance 2022-09-25 17:14:35 +09:00
238fc0799e Fixed statfs(free inodes) for macos 2022-09-25 17:10:37 +09:00
5b95a0fcb6 Fixed errors reported by cppcheck 2.9 (#2038) 2022-09-24 15:45:13 +09:00
1946ac415a Use man-page date instead of build date
to allow for reproducible builds of s3fs.1

This PR was done while working on reproducible builds for openSUSE.
2022-09-02 07:29:10 +09:00
2186317676 Include missing ctime header
This caused compilation errors on Fedora 36.
2022-09-01 22:40:16 +09:00
5ab1037094 Strictly reviewed the exclusive control of PseudoFdInfo class(additional change) 2022-08-08 07:51:49 +09:00
f6d7ff1084 Strictly reviewed the exclusive control of PseudoFdInfo class 2022-08-07 20:41:35 +09:00
3e242d0bad Avoid C-style casts (#2015)
Prefer more precise C++-style casts.
2022-07-30 22:35:27 +09:00
c491fbeabc Replace uses of lock_already_held flag with AutoLock::Type 2022-07-30 16:20:43 +09:00
e654e8ec8a Removed const_cast in set_bucket 2022-07-30 16:18:52 +09:00
48e9e51f4f Remove more unneeded headers identified by IWYU (#2011) 2022-07-30 12:06:47 +09:00
5a2172dc56 Fixed data race and memory leaks in PseudoFdInfo 2022-07-30 06:51:16 +09:00
07535ec3ec Address clang-tidy warnings (#2010) 2022-07-29 22:00:07 +09:00
b8dd466988 Fixed data race in ThreadPoolMan 2022-07-29 13:24:09 +09:00
01a92476e6 Remove unneeded headers identified by IWYU (#2007) 2022-07-28 23:38:38 +09:00
3928a7e359 Remove more uses of const_cast (#2006)
Follows on to #2004.
2022-07-28 23:37:15 +09:00
f9f614a474 Avoid mutating mybasename and mydirname parameters (#2004)
basename and dirname mutate their inputs but const_cast hid this
behavior.  Also shuffle helpers to avoid unnecessary std::string.
Follows on to 404c284440.
2022-07-28 23:34:01 +09:00
e30a5939d0 Fixed deadlock in S3fsCurl::DestroyCurlHandle 2022-07-28 13:47:27 +09:00
4b2f3fecb5 Set mtime/ctime/atime of all objects as nanosecond 2022-07-28 13:47:03 +09:00
ccfc119e45 Improved to avoid unnecessary head request 2022-07-27 21:51:28 +09:00
11adf11957 Changed the time(a/c/m) acquisition of stat to nanosecond string 2022-07-25 07:21:37 +09:00
38b5018bab Remove unneedd binary_function inheritance (#1998)
GCC 12 warns that C++17 removes this.
2022-07-24 22:41:58 +09:00
404c284440 Fixed race condition in dirname and basename call 2022-07-24 18:14:58 +09:00
e0655008b3 Protect pending_status in UploadPending (#1992)
This requires avoiding double-locking in RowFlush.  References #1991.
2022-07-22 23:30:04 +09:00
22f2392fca Fixed bugs about stream upload 2022-07-19 21:29:56 +09:00
136c5ec653 Fixed a bug in the test_external_creation test 2022-07-18 22:34:53 +09:00
faddb4900f Merged the code corresponding to the mknod fix(f11eb7d) 2022-07-17 22:20:45 +09:00
6ca7d5ec27 Fixed an error which reported by cppcheck 2.8 2022-07-17 22:20:45 +09:00
6f679a9e78 Reflect the result of the review in the code again 2022-07-17 22:20:45 +09:00
b0eeaa6679 Reflected the result of the review in the code 2022-07-17 22:20:45 +09:00
d22e1dc018 Add the stream upload which starts uploading parts before Flush 2022-07-17 22:20:45 +09:00
3a0799ec18 Re-re-re-fix propagating the return code (#1984)
This shell incantation is necessary to have errexit take effect for
test bodies.  Previous only the _last_ command's exit code was
propagated to the test runner, masking real failures.  Reverts
ea3c21f270.
2022-07-17 02:13:06 +09:00
4e163b2888 Allow listing implicit directories (#1986)
This fixes an issue when using -o notsup_compat_dir flag, dating back
to its introduction 3ac39d61f8.  The new
default exposed this in my local testing but a test runner bug masked
a test failure in test_external_directory_creation.  References #927.
References #1984.
2022-07-17 01:54:29 +09:00
86da2eed3a Do not call exit in individual test functions (#1985)
This could prevent the test runner from reporting failures.
2022-07-17 01:33:50 +09:00
e7ed01b35f Consume return code from get_object_attribute (#1976)
Found via clang-analyzer.
2022-07-09 16:45:23 +09:00
4d303caa62 Add Valgrind to sanitizer script (#1978)
Theoretically msan can do this but practically it requires a custom
libc++.
2022-07-09 16:40:23 +09:00
3f55c98a3f Fixed a bug when the pool of curl handler exceeds the upper limit 2022-07-08 21:14:29 +09:00
2723e1049e Add missing paragraph to help (#1974) 2022-07-03 12:35:02 +09:00
f11eb7d69b Fixed a bug that regular files could not be created by mknod 2022-06-29 16:56:19 +09:00
73b49c1038 Fixed a bug that regular files could not be created by mknod 2022-06-29 16:56:19 +09:00
4bec68713a Add CSI for S3 to references (#1971) 2022-06-28 22:56:12 +09:00
8b90cd6ba1 Enable notsup_compat_dir by default (#1970)
Few applications create the dir_$folder$ objects and users can enable
compat_dir if required.  This commit reduces readdir latency by 33%.
Also remove notsup_compat_dir from tests since these directories are
never created.  Fixes #927.  References #1643.
2022-06-28 07:56:06 +09:00
ac72bf34dd Run test_external_directory_creation for all flags (#1969) 2022-06-28 07:50:24 +09:00
a282cb7a84 Update CI runners to Fedora 36 and Ubuntu 22.04 (#1965)
Also remove Debian stretch which is no longer supported by LTS.
2022-06-22 17:40:08 +09:00
b52f916af6 Avoid extended initializer lists in C++03 (#1960)
C++11 introduces these.
2022-06-12 23:52:16 +09:00
ec7810f08e Fixed a bug could not change the mode while the file was opened 2022-06-12 13:48:42 +09:00
904682b856 Fix double-iteration in curl_slist_remove (#1951)
Also backfill tests.  Fixes #1948.
2022-05-27 22:56:20 +09:00
92fd5bc3e1 Fixed errors reported by cppcheck 2.8 (#1949) 2022-05-26 01:48:53 +09:00
d75c6d6538 Changed the message level(ERR to INFO) of skip cleanup cache (#1946) 2022-05-22 14:36:56 +09:00
a30beded1c Removed unnecessary debug options for aws command 2022-04-22 22:36:06 +09:00
df7bbb28d5 Replace awscli version 1 to 2 2022-04-19 23:11:25 +09:00
dc40f16161 Upgrade to S3Proxy 2.0.0 (#1929)
Release notes:

https://github.com/gaul/s3proxy/releases/tag/s3proxy-2.0.0

This enables Java 17 compatibility.
2022-04-04 23:03:16 +09:00
1abfb7e965 Reference docker-s3fs-client (#1925) 2022-03-21 20:44:07 +09:00
d2d75787d2 Specify bash strictness options (#1924) 2022-03-12 17:01:27 +09:00
5c57e17b77 Enable noobj_cache by default (#1922)
This should improve performance in many situations.  s3fs already
enables the stat cache by default so memorizing noobj makes this more
consistent.  Fixes #1901.
2022-03-12 16:57:31 +09:00
deaa85c40e Document glacier_ir storage class (#1921)
Announcement:
https://aws.amazon.com/about-aws/whats-new/2021/11/amazon-s3-glacier-instant-retrieval-storage-class/

This does not require code changes due to
bbcccd6e98.
2022-03-12 16:20:38 +09:00
49d92c7022 Update ChangeLog and configure.ac for 1.91 (#1920)
Fixes #1876.
2022-03-08 07:48:15 +09:00
d842d45b2b Fixed a bug about truncation for shrinking file 2022-03-02 22:41:10 +09:00
684ced5a41 Changed handling the credential in S3fsCred more robust 2022-03-02 22:39:15 +09:00
afb0897553 Typos 2022-02-24 19:15:00 +09:00
8a5c4306f5 Preserve sub-second precision where possible (#1915) 2022-02-23 23:58:51 +09:00
01e24967b6 Add test for external object creation (#1900)
This test demonstrates the behavior before and after the stat cache
timeout when using noobj_cache.
2022-02-23 23:34:58 +09:00
08adffd2fe Fix typos (#1916) 2022-02-23 23:31:52 +09:00
0842c5718f Use more new file names for every test (#1902)
This makes the tests more robust.  Also fix filename to end in .txt.
2022-02-23 22:59:21 +09:00
5452e9cb10 Dynamically generate dates for man page file 2022-02-23 21:51:47 +09:00
232ff28cc7 Re-re-fix propagating the return code (#1903)
Previously the integration tests were exiting after the first failed
test instead of running all of them an reporting their statuses.
Follows on to dbf93c0152.
2022-02-23 14:27:29 +09:00
81ed2bd91e Propagate deferred exit status from main (#1912)
Previously s3fs always returned zero when the bucket did not mount.
Fixes #1911.
2022-02-23 10:09:12 +09:00
305d660e39 Use custom CA bundle instead of ignoring errors (#1910)
Fixes #1846.
2022-02-23 10:04:05 +09:00
a716c72d37 Update notsup_compat_dir in --help 2022-02-21 19:29:15 +09:00
302150b4f5 Filter mountpoints via mount -t (#1905)
This is portable between Linux and macOS.
2022-02-20 20:49:35 +09:00
3fa03d4e1e Pass explicit -p option to ps (#1904)
This ensures that a pid follows.
2022-02-20 20:40:29 +09:00
e014d6e646 Changed Rocky Linux 8 instead of CentOS 8 2022-02-20 19:29:34 +09:00
c2a49b7b1a Rephrase the description of notsup_compat_dir 2022-02-20 16:06:57 +09:00
265fa9e47a Add performance considerations section to man page 2022-02-20 16:06:57 +09:00
d31cbda7b6 Fixed a bug about checking credential 2022-02-19 23:22:15 +09:00
b64dc7749c Moved parameter analysis processing to S3fsCred class 2022-02-19 17:23:40 +09:00
b9e2be5c21 Fixed two typos in configure.ac 2022-02-19 17:22:43 +09:00
839a33de49 Fixed not to call Flush even if the file size is increased (#1887)
Changed s3fs_truncate function.
This change reduces the number of file uploads if the file size is changed.

On macOS, I have found that the truncate call when "size=0" cannot reflect the file size.(This reason is not understood...)
To avoid this, only when "size=0", the flush method is called as before.

Other than that, I found a bug in FdEntity::Open() and fixed it.

Fixes #1875.
2022-02-15 21:29:07 +09:00
4dfe2bfdd7 Include climits to support musl libc
PATH_MAX constant is not visible from any of currently included header
files in system with musl libc, where compilation fails with an error
below. The constant is defined in limits.h which is directly include via
climits header file.

fdcache.cpp: In static member function 'static FILE* FdManager::MakeTempFile()':
fdcache.cpp:381:14: error: 'PATH_MAX' was not declared in this scope
  381 |     char cfn[PATH_MAX];
      |              ^~~~~~~~

Fixes: d67b83e671 ("Allow configuration for temporary files directory")
2022-02-14 09:19:30 +09:00
1678803566 Added S3fsCred class and moved Credential related processing in it 2022-02-13 21:38:30 +09:00
d7e929e0a8 Fixed some Github Actions errors. (#1886)
- Fix knownConditionTrueFalse cppcheck(2.7) error on MacOS
- Fixed package installing failure of appstream download on centos8
2022-02-13 14:23:35 +09:00
94e8e23eef Fixed test_external_directory_creation test when cache enabled (#1885) 2022-02-13 13:32:19 +09:00
dbf93c0152 Propagate return code properly (#1884)
Previously this did not propagate test failures.  A bad rebase
introduced this logic in 495d51113c.
2022-02-06 22:45:20 +09:00
9224f792f0 Use CLOCK_REALTIME for UTIME_NOW (#1881)
Previously s3fs_utimens used CLOCK_MONOTONIC_COARSE which was not
1970-based.  Found via pjdfstest.  References #1589.
2022-01-30 22:19:15 +09:00
f6ed972926 Always flush open files with O_CREAT flag (#1879)
Previously s3fs only created files that had dirty data and not those
with zero-bytes.  Regression from
771bbfeac5.  References #1013.  Found
via pjdfstest.  References #1589.
2022-01-30 22:02:37 +09:00
0c75a63184 Preserve sub-second precision with utimens (#1880)
Found via pjdfstest.  References #1589.
2022-01-30 21:45:51 +09:00
30cf7a50bb Added stat check for subdir created with awscli 2022-01-30 18:31:36 +09:00
e452ef3940 Fixed the fault tolerance when time stamp getting fails 2022-01-30 18:31:36 +09:00
cd5a69b9eb Handle UTIME_NOW and UTIME_OMIT special values (#1868)
FUSE 3 will require this behavior.  References #1159.
2022-01-29 11:35:37 +09:00
74c11ef226 Check bucket before trying to create it (#1874)
This makes it easier to run tests against S3 other than S3Proxy.
2022-01-26 23:42:12 +09:00
662882d2f0 Always call clock_gettime(2) (#1871)
e01ded9e27 introduced this compatibility
shim but macOS 10.12 (2016) added this:
https://stackoverflow.com/a/39801564 .  Also remove fallback to
time(3) which loses precision.
2022-01-25 08:36:27 +09:00
de0c87c801 Convert S3FS_LOW_LOGPRN from a macro to a function (#1869)
This shrinks the binary size from 770 to 540 KB and reduces compile
times.
2022-01-23 23:10:09 +09:00
41aaa4184f Avoid double setting values in statfs 2022-01-23 21:49:51 +09:00
451602e58d Remove unnecessary conditional for automake 2022-01-23 21:49:51 +09:00
581f5c0356 Move strptime polyfill to string_util 2022-01-23 21:49:51 +09:00
e5f6f112db Fix typo 2022-01-23 21:49:51 +09:00
b3cef944b2 Fix test_page_list_SOURCES has no if MSYS clause 2022-01-23 21:49:51 +09:00
6edb6067f3 Remove strcasestr polyfill 2022-01-23 21:49:51 +09:00
b2c659c0a6 Disable compiling polyfills in not MSYS2 env 2022-01-23 21:49:51 +09:00
807ea52ba7 Remove duplicates in .gitignore 2022-01-23 21:49:51 +09:00
3ac9f571f5 Use std::get_time instead in strptime polyfill 2022-01-23 21:49:51 +09:00
d95a612548 Revert "Run autoupdate"
This reverts commit 0b1d801598164c45e7c9e89ebd30ddde8251befa.
2022-01-23 21:49:51 +09:00
19303a546e Fix the statfs issue, using f_frsize instead 2022-01-23 21:49:51 +09:00
4d117fd0af Add instructions for Windows compilation 2022-01-23 21:49:51 +09:00
2bf84fc705 Ignore .exe files 2022-01-23 21:49:51 +09:00
70692ee770 Run autoupdate 2022-01-23 21:49:51 +09:00
6370e150dd Disable features that causes problems on Windows 2022-01-23 21:49:51 +09:00
b14e39815b Use polyfills in MSYS2 environment 2022-01-23 21:49:51 +09:00
6aaf9433a5 Add polyfills for MSYS2 environment 2022-01-23 21:49:51 +09:00
46014397d8 Added test by a shell script static analysis tool(ShellCheck) 2022-01-22 22:23:08 +09:00
93d1c30d4d Use XML parsing with PUT HTTP 200 responses (#1858)
This works around the missing strcasestr on win32.  References #728.
2022-01-14 16:10:22 +09:00
6300859c80 Prefer = over == for older shell compatibility (#1857) 2022-01-14 12:40:55 +09:00
2892d3b755 Call curl --fail to propagate exit code (#1856) 2022-01-14 11:52:52 +09:00
25012f3839 Fix typo in -o enable_unsigned_payload 2022-01-12 22:50:49 +09:00
3dfc1184ca Remove python2 from bullseye 2022-01-10 19:34:36 +09:00
53d1b04cc2 Add new suppressions for clang-tidy 13 (#1847) 2022-01-09 21:42:36 +09:00
b67465b91d Specify C++03 for CI (#1850) 2022-01-09 20:48:09 +09:00
cba65fc51a Remove Python 2 (#1849) 2022-01-09 20:37:15 +09:00
75b16c72aa Build s3fs in parallel (#1848)
GitHub runners provide 2 Linux CPUs or 3 macOS CPUs:

https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources
2022-01-09 20:22:49 +09:00
577e2bc987 Generate S3Proxy SSL certificate during tests (#1845)
Also provide CA bundle to AWS CLI to work around CI failures instead
of ignoring errors.  Fixes #1812.
2022-01-09 15:13:36 +09:00
adb58af17b Annotate local variables (#1844)
This prevents collisions with other globals.  Fixes #1843.
2022-01-09 13:03:36 +09:00
dd11de3a50 Add Debian Bullseye to CI (#1842)
Stretch is supported until June 2022:

https://wiki.debian.org/LTS
2022-01-09 12:11:00 +09:00
fc7543fa25 Make ut_test compatible with Python 3 (#1838)
This may allow removing Python 2 on newer distros.

Co-authored-by: Takeshi Nakatani <ggtakec@gmail.com>
2022-01-09 11:08:36 +09:00
a44ea7c12a Replace write_multiple_offsets.py with write_multiblock (#1837)
This reduces the dependency on Python 2.
2022-01-09 10:51:17 +09:00
e734763002 Remove createbucket option (#1841)
AWS CLI can do this.  Fixes #1840.
2022-01-05 01:59:31 +09:00
37af08bacf Use JRE instead of JDK for Debian-based distros (#1839)
This reduces the dependencies installed.  It does not appear that
Fedora-based distros support this.

Co-authored-by: Takeshi Nakatani <ggtakec@gmail.com>
2022-01-05 01:29:06 +09:00
616db5bf1c Prefer curl over wget for fetching dependencies (#1836)
The former is lighter-weight and libcurl is already a dependency for
s3fs.
2022-01-05 00:43:36 +09:00
9ad9c382f4 Update README.md
Fixed install error
2022-01-04 22:44:49 +09:00
1d090aa7a3 Install default-jdk-headless instead of default-jdk
This reduces the dependencies installed.
2022-01-04 18:18:24 +09:00
61e9029be4 Fix typos in CI scripts 2022-01-03 19:50:13 +09:00
5de92e9788 Bump CI to Fedora 35 (#1806) 2021-12-02 23:45:19 +09:00
85ca2a3e45 fix mixupload return EntityTooSmall while a copypart is less than 5MB after split (#1809)
* fix  mixupload return EntityTooSmall while a copypart is less than 5MB after split
* fix possible part exceeds 5GB when multipart_copy_size is set to 5120MB
* Update curl.cpp
Co-authored-by: liubingrun <liubr1@chinatelecom.cn>
2021-11-27 16:53:26 +09:00
07e2e3f72a Remove sleep 1 from test_update_directory_time (#1803)
Reduces per-flag test run-time by 5 seconds.
2021-11-04 08:16:40 +09:00
3cf00626a2 Add option to allow unsigned payloads (#1801)
This reduces CPU usage of sigv4.  This reduces test run-time by 7
seconds per flag.
2021-11-01 23:33:55 +09:00
e289915dcb Remove require-root script (#1800)
Tests do not require this.
2021-10-31 10:48:15 +09:00
06dec32965 Use AWS CLI to create explicit times in the past (#1797)
s3fs can also do this via utimensat but tests should not trust this.
Also break tests into individual functions.  This further reduces test
run-time 8 seconds per flag.
2021-10-30 10:54:18 +09:00
86317dd185 Replace dd if=/dev/urandom with junk data generator (#1786)
This reduces test run time for a single flag from 73 to 60 seconds.
2021-10-28 22:54:25 +09:00
473da56abf Use default JDK instead of forcing Java 8 (#1796)
S3Proxy requires Java 8 or later, not 8 specifically.
2021-10-28 22:27:48 +09:00
162ab14517 Bump Ubuntu CI to latest non-LTS version (#1794) 2021-10-28 22:10:20 +09:00
40d2e0d1ad Reduce sleep time to 1 (#1793)
This reduces test run-time 15 seconds per flag or 2.5 minutes when
testing all flags.
2021-10-27 23:47:08 +09:00
b6c5069ef7 Fixed the test is multi-block writing by one flush 2021-10-27 08:19:05 +09:00
7273d561f5 Added exclusive control of statc variables in s3fs xml parser 2021-10-27 08:18:19 +09:00
78126aea0b Added exclusive control of statc variables in s3fs xml parser 2021-10-27 08:18:19 +09:00
7892eee207 Fixed a bug that copied without considering the length of xmlChar 2021-10-27 08:18:19 +09:00
72a9f40f3f Update to S3Proxy 1.9.0 (#1788)
Notably this fixes an issue with the transient provider reading parts
of large files.

Release notes:

https://github.com/gaul/s3proxy/releases/tag/s3proxy-1.9.0
2021-10-26 23:20:52 +09:00
495d51113c Remove unneeded sleeps from tests (#1784)
Also use a unique file name for every test.  This ensures that tests
like test_external_directory_creation and test_external_modification
do not collide.
2021-10-26 23:19:14 +09:00
0abeec9cae Simpily errexit modifications 2021-10-26 21:47:36 +09:00
ea3c21f270 Reduce errexit modifications (#1785)
This is less error prone but requires some magic && ||.
2021-10-25 23:53:45 +09:00
23fe6f4dee Fixed parse_string function in write_multiblock.cc 2021-10-25 17:56:49 +09:00
34ea2acd75 Add a test that is multi-block writing by one flush 2021-10-25 17:56:49 +09:00
ea64886469 Fixed a bug in test_(zero_)cache_file_stat test function 2021-10-24 18:24:12 +09:00
023aaf7dff Fixed wrong stat of cache after new creation file
And added a test for stat of cache after new creation file
2021-10-17 16:10:14 +09:00
2f412804e2 Fixed forgetting to clear the dirty flag for meta information
Addressed an error in macos cpp check
2021-10-15 22:54:55 +09:00
d6ffd389da Excluded ubuntu 16.04 from the CI build execution environment 2021-10-15 08:54:13 +09:00
be0b17329a Fix wrong function name in log message (#1774) 2021-10-10 11:08:32 +09:00
b4edad86d6 remove Expect: 100-continue header when requesting an IMDSv2 access token 2021-09-09 08:12:36 +09:00
9d1552a54e fix IAM role retrieval from IMDSv2
AWS IMDSv2 support was added in #1462, but the implementation did not
cover the addional IMDS access that occurs with the iam_role=auto
configuration.  This change implements IMDSv2 support for the IMDS
call to determine the instance's role name.

See also
https://stackoverflow.com/questions/69031023/how-to-make-s3fs-use-imds-v2-when-mounting-s3-buckets-from-ec2-instance
2021-09-03 20:36:34 +09:00
47ebfcc60a Consume return value from curl_easy_setopt (#1759)
Found via Coverity.
2021-09-02 08:07:06 +09:00
beecf32dff fclose(FILE*) instead of close(fileno(FILE*)) (#1758)
This is the same thing but confuses Coverity.
2021-09-01 19:41:55 +09:00
57b2e4a4f1 Fix 32-bit compilation issues (#1757) 2021-08-31 19:36:02 +09:00
48817d849f Require explicit length in s3fs_decode64 (#1755)
This is available from std::string::size in callers.
2021-08-31 09:22:10 +09:00
d9f2d17040 1. fix RowFlush can not upload last part smaller than 5MB using NoCacheMultipartPost; (#1753)
2. fix deadlock in UploadPendingMeta
2021-08-31 00:41:47 +09:00
cd98afdd7b Do not NUL terminate base64 decoded output (#1752)
This is binary data and must use the explicit length.
2021-08-31 00:15:47 +09:00
dac6885fb0 Don't over-allocate in base64 encoding and decoding (#1751) 2021-08-30 00:03:10 +09:00
fcd180891b fix misuse of IsUploading (#1747)
Co-authored-by: liubingrun <liubr1@chinatelecom.cn>
2021-08-29 23:41:02 +09:00
d5d541c7f7 Adding FreeBSD example to README
S3FS has existing on FreeBSD since 2009, and should be reflected here that it is well supported.
2021-08-26 10:18:56 +09:00
a868c0656e Changed etaglist_t from string list to new structure etagpairs list 2021-08-16 09:27:12 +09:00
cd466ebdd4 Update ChangeLog and configure.ac for 1.90 (#1739)
Fixes #1737.
2021-08-08 14:01:19 +09:00
15e89b78de Add a partial page_list unit test (#1735) 2021-08-04 07:36:32 +09:00
66006ba48d Add dedicated upper- and lower-case hex functions (#1734)
This makes the call sites more readable than a boolean parameter.
2021-08-04 07:28:51 +09:00
18e9c62087 Make string constants read-only const (#1733)
This removes some global constructors.  Also use a consistent ALL_CAPS
style.
2021-08-03 00:10:27 +09:00
34f89e5936 Added fake_diskfree option to deceive free disk space for test 2021-08-02 11:04:42 +09:00
e1f3b9d8c1 Add support for AWS-style environment variables (#1729)
Support AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_SESSION_TOKEN
in addition to the AWSACCESSKEYID, AWSSECRETACCESSKEY and
AWSSESSIONTOKEN.

The old environment variables are still supported, but they are
deprecated and no longer documented.

Close #1708
2021-07-26 23:29:45 +09:00
d3278f4886 Loosen CheckBucket to check only the bucket (#1728)
Previously it checked if there was an object present, assuming that
this was a directory object normally created for s3fs directories.
However most S3 clients do not create this object for virtual folders.
Fixes #1460.  Fixes #1687.
2021-07-25 12:29:00 +09:00
77f0b75d2f Add jitter to avoid thundering herd (#1723) 2021-07-25 10:22:19 +09:00
012e6dd8a2 Fix README nit (#1726) 2021-07-22 13:54:20 +09:00
199b3d4709 Fixed a bug in disk free space calculation 2021-07-18 14:52:11 +09:00
7890989cbb Address cppcheck 2.5 warnings (#1720)
This slightly simplifies memory management.
2021-07-14 22:18:09 +09:00
945cc2ac54 Added UntreatedParts class instead of untreated upload info members in PseudoFdInfo 2021-07-12 21:45:29 +09:00
c30acbbf90 Splited some methods of FdEntity class by uploading mode
- Splited FdEntity::Write method by uploading mode
- Splited FdEntity::RowFlush method by uplading mode
2021-07-10 17:24:34 +09:00
881025cc9e Add initiator pid, uid and gid to a debug log (#1716) 2021-07-10 16:23:20 +09:00
4cc210c5ab Prevents the etag string buffer from being destroyed during use
and absorbed MPPART_INFO structure into filepart structure
2021-07-03 22:42:18 +09:00
2d5316a334 Fixed 1710 - Added a flag for check in Linux 2021-07-02 11:34:51 +09:00
9cfa177af0 Add flag to run all tests (#1710)
This allows CI to run the full set of tests while making local
development faster.
2021-07-02 08:41:47 +09:00
fe44355d25 Report s3fs space as 18.4 EB (#1709)
256 TB probably seemed large in 2007 but in 2021 it is small enough to
confuse some users.
2021-07-02 07:56:05 +09:00
487df27008 Return EREMOTE when reading Glacier objects (#1705)
Previously s3fs returned EIO which was not helpful to the caller.
Returning a more specific error code allows automatically restoring
the object via RestoreObject in a subsequent commit.
References #1466.
2021-06-30 09:25:36 +09:00
1965916f7a Convert storage class values to uppercase (#1704)
AWS requires uppercase values.  Fixes a regression from
bbcccd6e98.  References #1613.
2021-06-30 09:03:31 +09:00
8948eded09 Address clang-tidy warnings (#1703) 2021-06-30 08:42:44 +09:00
2f59cb5a0a Remove unneeded volatile qualifiers (#1702)
We should use proper locking instead.  Specifically for
is_meta_pending this does not do what was intended due to the
read-modify-write of the member.
2021-06-30 08:20:44 +09:00
f505c8224e Explicitly specify lock type (#1701)
This makes it more clear and type-safe if the caller already has the
lock.  Follows on to 84174c560d.
2021-06-27 15:15:48 +09:00
2154e898bc Fix typos (#1700) 2021-06-27 11:22:33 +09:00
f9e80f995d Fixed a bug about rename existing file of different sizes by mpcopy 2021-06-26 00:04:58 +09:00
a5c1915772 Set CURLOPT_UNRESTRICTED_AUTH when authenticating (#1681)
This is necessary for authentication to work with AWS when it responds with 307 to the check bucket request when mounting. This happens to newly created buckets according to https://aws.amazon.com/premiumsupport/knowledge-center/s3-http-307-response/.

Prior to this, curl would follow the redirect, but would not include the `Authorization` header which would end up with `404`.

Co-authored-by: Takeshi Nakatani <ggtakec@gmail.com>
2021-06-25 20:26:12 +09:00
6edf3d6427 Updated to clearly output message about the file descriptor type(pseudo/physical) 2021-06-25 19:18:08 +09:00
944c1fd148 Clean up litter in ut_test (#1697) 2021-06-25 19:15:03 +09:00
20281737b1 Set explicit Content-Length: 0 when initiating MPU (#1696)
This works around a GCS quirk that incorrectly requires this header.
Fixes #1661.
2021-06-25 18:36:40 +09:00
0555c4216e Added test case for utimens is calling during multipart upload 2021-06-21 17:20:24 +09:00
5b6684ca19 Fixed a bug utimens is calling before flush 2021-06-21 17:20:24 +09:00
c4ac923b4c Ensure NUL-terminated result after strncpy (#1694)
Long symlinks may cause that the result buffer is filled and not proper
terminated with a null byte.
2021-06-21 08:08:56 +09:00
cc022a68f4 Fixed a bug in s3fs_write 2021-06-20 23:13:44 +09:00
1571379304 Set LC_ALL=en_US.UTF-8 in tests (#1691)
This allows tests to pass using the S3Proxy filesystem provider.
References #1665.
2021-06-20 19:27:25 +09:00
858562ed53 Fixed comparison warning for size_t variable 2021-06-20 16:53:25 +09:00
b8724425d3 Require explicit base parameter in cvt_strtoofft (#1683)
Also convert most callers of cvt_strtoofft to base 10 which avoid the
magical behavior of interpreting a leading 0 as octal.
References #1682.
2021-06-20 11:00:15 +09:00
b9ce0faee2 Set Content-MD5 header even for empty objects
The Content-MD5 header is required for any request to upload an object
with a retention period configured using Amazon S3 Object Lock
2021-06-19 16:10:58 +09:00
1e0e2752bf Improve warning for terminated threads
with non-zero return code.
2021-06-18 07:54:38 +09:00
7a488b93d0 Set decimal base for converting subseconds to int
The leading 0 triggers an automatic conversion as an octal value. This
fails because it is a decimal value.

Setting the base to 10 prevents this automatism and treats the value
as a decimal value.

Fixes: [WAN] string_util.cpp:cvt_strtoofft(96): something error is occurred in convert std::string(017080564) to off_t, thus return 0 as default.

Related to #1676
2021-06-17 06:27:02 +09:00
d67b83e671 Allow configuration for temporary files directory 2021-06-16 21:29:58 +09:00
a100be9dce Prefer std::string::empty over length == 0 (#1679)
This is more concise.
2021-06-13 20:03:10 +09:00
4d39ea887e Protect orgmeta with fdent_lock (#1678)
Fixes a crash seen with the CentOS 7 builder and when running with
AddressSanitizer.  Regression introduced by
ac578d188e.  Fixes #1677.
2021-06-13 16:14:24 +09:00
7638b5b3e3 Prefer std::string::rbegin over operator[] (#1673)
This is more concise and safer due to not repeating the variable name.
We cannot use std::string::back since it is not available in C++03.
2021-06-13 13:26:38 +09:00
600cee118d Fix implicit narrowing conversions (#1672)
These do not appear to be problematic but rather just clean up warnings.
Found via clang -Wshorten-64-to-32.
2021-06-13 12:50:07 +09:00
c2c56d0263 Added info object about multipart uploading for each pseudo fd
(and fixed typo about method name)
2021-06-04 22:42:58 +09:00
ac578d188e Introduced pseudo fd and separated fd for each file opening 2021-06-04 22:42:58 +09:00
53dfd48f59 Correct usage of istringstream (#1670)
Previously this looped one more time than necessary due to the eof
check:

https://isocpp.org/wiki/faq/input-output#istream-and-eof

Remove now redundant empty check.
2021-06-02 07:14:32 +09:00
f5701fa9ad Correct typo in undefinedsanitizer config (#1669) 2021-05-29 22:07:33 +09:00
84174c560d Fix data races caused by incorrect locking (#1668)
Found via Threadsanitizer.  Fixes #1471.
2021-05-29 00:11:55 +09:00
9bf525ee7a Ensuring multipart size even when storage is low
When the temporary storage was full, the old implementation started an
upload even if there was not enough data to completely fill the minimum
multipart size or fill the user-selected multipart size.

The new implementation ensures the minimum multipart size by forcing
the user-selected multipart size.

Fixes #1591
2021-05-27 22:55:52 +09:00
4b69d4b1bb Fixed a bug when the disk capacity was insufficient in RowFlush 2021-05-22 23:11:46 +09:00
bbcccd6e98 Make storage class a string (#1663)
This allows non-standard storage classes like Google Cloud Storage
Nearline.  Fixes #1613.
2021-05-21 23:34:31 +09:00
c0bcb41175 Increase test robustness by adding LC_ALL=C (#1660)
Use C locale, because some tests check for English expressions

Fixes #1658
2021-05-20 21:19:50 +09:00
b5fef788da Additional bug fixing for not creating zero-byte object 2021-05-09 17:33:53 +09:00
42f5965d8a Fix off_t to int narrowing in PageList::GetSparseFilePages (#1654)
Found via clang-tidy.
2021-05-09 14:35:00 +09:00
d904d91252 Prefer std::map::insert over find and operator[] (#1653)
This avoids a duplicate lookups.
2021-05-09 14:11:35 +09:00
4d81a4bf68 Use same time when creating directory objects (#1652)
This avoids mismatched times and is slightly faster.
2021-05-09 13:44:59 +09:00
9abe3fa662 Use same time when creating directory objects (#1652)
This avoids mismatched times and is slightly faster.
2021-05-09 13:44:12 +09:00
9d8f1b00f7 Fixed make_random_string test code being slow on macos 2021-05-08 13:55:39 +09:00
bb6d2b1b74 Replace snprintf with string and ostringstream (#1649)
These uses are probably safe from a buffer overflow perspective but
can cause data race issues in logging due to static buffers.
2021-05-08 02:48:47 +09:00
096a230b70 Allow arbitrary size AWS secret keys (#1648)
Previously s3fs limited these to 123 characters.  Fixes #1626.
2021-05-06 22:24:38 +09:00
8ef01d37a9 Fix a few nits (#1645)
Make some strings more const, initialize members, and abort if lock
initialization fails.  Partially found via clang-tidy.
2021-05-06 19:40:35 +09:00
cb9148f6cd Update for clang-tidy 12 (#1644) 2021-05-03 09:43:18 +09:00
c4fa53ec8b Add section about storage consumption to manpage (#1639)
References s3fs-fuse#1591. References s3fs-fuse#1595.
2021-05-01 15:09:29 +09:00
1e2df406ee Add Ubuntu 21.04 to CI (#1642) 2021-04-30 23:51:55 +09:00
1dabfbe1da Update CI to latest Fedora version (#1641) 2021-04-30 20:29:28 +09:00
771bbfeac5 Do not create zero-byte object when creating file (#1640)
Previously s3fs created this object to store metadata and overwrote it
when flushing.  This prevented use with object stores which do not
allow overwrites like HDS.  Instead only create an in-memory
representation which reduces the time to create small files.
Fixes #1013.
2021-04-30 19:56:33 +09:00
3694786112 Propagate errno instead of EIO (#1638)
This improves error fidelity.  Follows on to
b70f8db037.  References #1523.
2021-04-30 07:09:00 +09:00
e477d7d186 Add note about Homebrew and FUSE (#1637) 2021-04-25 21:35:08 +09:00
fbf3c83019 Consider S3 errors in HTTP PUT 200 responses (#1635)
S3 can emit these in unusual situations.  Fixes #1317.
2021-04-25 13:18:11 +09:00
8a51a26819 Allow truncation of open and modified files
Regression introduced in f5bf41cf11.
Fixes #1575.
2021-04-25 12:35:35 +09:00
1838f52e19 Declare undefined symbols for fallocate function 2021-04-25 10:12:25 +09:00
e9eb248f2f Fail CheckBucket when S3 returns PermanentRedirect (#1630)
Previously s3fs allowed mounting but all operations returned EIO.
References #693.

Co-authored-by: Takeshi Nakatani <ggtakec@gmail.com>
2021-04-24 18:46:24 +09:00
77581eda59 Change in ibm iam endpoint 2021-04-21 21:42:55 +09:00
7f3e423bbe Preserve sub-second time precision (#1624)
Found via pjdfstests.  References #897.  References #1589.
2021-04-18 13:11:12 +09:00
706e3cbebd Update ctime and mtime when opening with O_TRUNC (#1623)
Found via pjdfstests.  References #1589.
2021-04-15 07:08:49 +09:00
2effffd8e2 Fixed codes for cppcheck 2.4.1 2021-04-13 21:12:35 +09:00
2908878988 Fixed codes for cppcheck 2.4.1 2021-04-13 21:12:35 +09:00
01a26a9011 Do not allow open with O_RDONLY and O_TRUNC (#1620)
Found via pjdfstests.  References #1589.
2021-04-13 07:28:10 +09:00
23e1fbf7b9 Update ctime when truncating file (#1619)
Found via pjdfstests.  References #1589.
2021-04-13 07:08:06 +09:00
ed2e877bb6 Return EACESS when lacking required executable bit (#1617)
This makes the check consistent with read and write.  Found via
pjdfstests.  References #1551.  References #1589.
2021-04-11 22:39:27 +09:00
3663082a01 Do not allow renaming to a non-empty directory (#1604)
Found via pjdfstests.  References #1589.
2021-03-28 19:10:52 +09:00
9645d57c05 Translate KeyTooLongError to ENAMETOOLONG (#1602)
AWS does not support keys longer than 1024 characters.  Add special
handling for HeadObject which does not have a response body.
Found via pjdfstests.  References #1589.
2021-03-28 13:17:41 +09:00
f6fbd75320 Return EFBIG when file exceeds multipart limit (#1600)
Found via pjdfstests.  References #1589.
2021-03-28 12:33:01 +09:00
20a6c9d35d Update to S3Proxy 1.8.0 (#1598)
Notably this fixes an issue with the filesystem backend which returned
the incorrect Content-Type for some directories.  It also reduces
memory use with GetObject using range requests with large objects.
References #1543.

Release notes:

https://github.com/gaul/s3proxy/releases/tag/s3proxy-1.8.0
2021-03-28 11:56:10 +09:00
0a90a40569 remove duplicate line from README.md 2021-03-27 19:03:15 +09:00
ef079f4e94 Don't ignore nomultipart when storage is low
When the temporary storage filled up, the old implementation uploaded
all data with multipart uploads, even if "nomultipart" was set.

The new implementation emits a warning and returns -ENOSPC instead.

Fixes #1595
2021-03-10 08:23:54 +09:00
b589ebec23 Output version and command parameters at startup 2021-03-06 19:11:57 +09:00
8c58ba8ac0 Update ChangeLog and configure.ac for 1.89 (#1584)
Also make formatting more consistent.  Fixes #1588.

Co-authored-by: Takeshi Nakatani <ggtakec@gmail.com>
2021-02-24 08:03:55 +09:00
a19d223434 Bypass an OSX test(no different from other OS) which takes very time consuming 2021-02-23 20:47:51 +09:00
fc06419549 Fixed aws command error by rsa on ubuntu16.04 (#1585) 2021-02-23 11:41:52 +09:00
032fcf2a47 Allow optional issuing of ListObjectsV2 (#1583)
This allows use of s3fs on object stores that do not implement
the V1 API.  Fixes #1573.
2021-02-23 09:45:13 +09:00
5b5bc3114a Fixed a bug that padded null bytes when changing xattr 2021-02-21 12:23:36 +09:00
81e267d421 Fixed the same bug in chmod/chown/utimens and added tests 2021-02-20 23:30:50 +09:00
4fc92d59f3 Fixed a bug that filling NULL bytes when changing the attribute after renaming 2021-02-20 23:30:50 +09:00
a0f347b10f Added no_time_stamp_ms option mainly for testing 2021-02-20 20:24:26 +09:00
5debf523b0 Allow changing temporary directory used for tests
Set temporary directory to $TMPDIR if set or use default /var/tmp
2021-02-19 13:59:23 +09:00
1c8aadafd1 Fix typo in an error message of the test suite 2021-02-19 13:59:23 +09:00
d33f252404 Fixed forgetting to clean up test files 2021-02-14 00:07:46 +09:00
4da56acdcc Improved processing when HEAD response is 400 2021-02-13 17:00:13 +09:00
493802a605 Fixed osx mistype declaration and typo warnings 2021-02-13 12:04:35 +09:00
22b0ae9d51 set IsExpireTime to true by default
fixes #1563
2021-02-12 12:20:47 +09:00
134a54b32f Allow configuring the multipart threshold (#1562)
Also change default which improves write performance for files >= 25
MB and <= 5 GB, particularly over lossy networks.

Co-authored-by: Takeshi Nakatani <ggtakec@gmail.com>
2021-02-11 23:35:46 +09:00
7f6fbb0021 Correct singlepart_copy_limit unit (#1561)
This is documented to be in MB not KB.

Co-authored-by: Takeshi Nakatani <ggtakec@gmail.com>
2021-02-11 22:53:50 +09:00
ec8bae9827 Do not periodically flush with nomultipartupload (#1559)
s3fs periodically flushes data to S3 and hole-punches the written
data, marking it as clean.  Without multipart copy, s3fs would write
the now-zeroed data along with any new data.  s3fs should not attempt
to periodically flush dirty data at all without multipart copy
support.  Fixes #1542.
2021-02-11 22:24:39 +09:00
a4d916af13 Allow configuring multipart copy size (#1555)
Also align configuration with mixupload.
2021-02-08 20:32:12 +09:00
32f096fa3f Use clock_gettime instead of gettimeofday 2021-02-08 10:19:28 +09:00
c692093921 Copy at most 5 GB per multipart copy part request (#1553)
Previously mixupload failed with larger objects due to the AWS
constraint on part sizes.  This symptom was seen more frequently due
to periodic flushing of dirty data.  Fixes #1547.
2021-02-07 23:10:07 +09:00
1a6d0826b5 Allow -1 value to disable max_dirty_data (#1552)
This matches the man page.
2021-02-07 22:14:31 +09:00
f2c5e38724 Allow integration tests to use larger files (#1548)
Previously these failed due to dd only copying 32 MB from /dev/urandom
and exhausting the limited space in /tmp.  References #1543.

Co-authored-by: Takeshi Nakatani <ggtakec@gmail.com>
2021-02-07 12:50:02 +09:00
bf33fe7f55 Increase buffer size to avoid warning (#1550)
This can be up to 54 bytes.

Co-authored-by: Takeshi Nakatani <ggtakec@gmail.com>
2021-02-07 12:26:58 +09:00
ff9d6a75c7 Parse more specific AWS error codes (#1549)
Fixes #1545.
2021-02-07 11:29:08 +09:00
4c6690f5f0 Add timestamps to debug log and cache integrity check (#1540)
* Add UTC timestamp to debug output

for easier correlation with external events

Old output:
$ s3fs mybucket /bucket/  -o curldbg,dbglevel=debug -d -d -f
[CRT] s3fs_logger.cpp:LowSetLogLevel(201): change debug level from...
[INF]     s3fs.cpp:set_mountpoint_attribute(3989): PROC(uid=0, ...

New output:
$ s3fs mybucket /bucket/  -o curldbg,dbglevel=debug -d -d -f
2021-01-28T21:09:16.264Z [CRT] s3fs_logger.cpp:LowSetLogLevel(202):...
2021-01-28T21:09:16.264Z [INF]     s3fs.cpp:set_mountpoint_attrib...

* Add UTC timestamp to cache integrity check

for easier correlation with external events.

$ s3fs mybucket /mybucket  -oset_check_cache_sigusr1=/tmp/check.cache

Old output:
$ kill -s SIGUSR1 $(pgrep s3fs)
$ cat /tmp/check.cache
------------------------------------------------------------
Check cache file and its stats file consistency
------------------------------------------------------------
------------------------------------------------------------
Summary - Total files:                0
          Detected error files:       0
          Detected error directories: 0
------------------------------------------------------------

New output:
$ kill -s SIGUSR1 $(pgrep s3fs)
$ cat /tmp/check.cache
---------------------------------------------------------------------------
Check cache file and its stats file consistency at 2021-01-30T13:04:14.111Z
---------------------------------------------------------------------------
---------------------------------------------------------------------------
Summary - Total files:                0
          Detected error files:       0
          Detected error directories: 0
---------------------------------------------------------------------------

* Fix indentation of S3fsLog::GetCurrentTime()
2021-02-04 10:41:29 +09:00
67b9381825 Remove limit for single-part objects
AWS enforces a 5 GB limit for single-part objects but other S3
implementations like GCS support larger objects.  Fixes #1542.
2021-02-04 09:19:37 +09:00
4b53d4bf6b Suppress spurious SHA256 error message (#1544) 2021-02-04 07:28:51 +09:00
ed85b72bf5 Add warning for failing metadata updates of large files
Metadata updates fail for large files if "-o nocopyapi" or
"-o nomultipart" is set.

This change is related to #1528
2021-01-28 10:20:32 +09:00
17fda89ae9 Handle s3fs_get_content_md5 and s3fs_sha256_hex_fd errors (#1534)
Follows on to 4d833a4fb9.
2021-01-25 19:08:14 +09:00
1987bcbea3 Re-fix retry logic (#1533)
This logic has always been broken but happened to try one time due to
&& operator precedence.  7158e50ee2
broke this further when quoting && since the command was not
evaluated.
2021-01-25 18:32:40 +09:00
d019dda4f7 Simplify substr manipulations with erase (#1532)
This avoids creating a new std::string.
2021-01-25 18:02:32 +09:00
dc9255bc5f Prefer static_cast where possible (#1531) 2021-01-25 08:15:17 +09:00
b0e8758b63 Use result instead of res for consistency (#1530) 2021-01-25 07:56:10 +09:00
6d65e30dd5 Fixed brew install with cask in github actions workflow 2021-01-21 17:34:03 +09:00
b70f8db037 Propagate errno from get_local_fent (#1525)
Follows on to 4d833a4fb9.
References #1523.
2021-01-20 23:21:14 +09:00
4d833a4fb9 Return more specific errno when available (#1520)
Previously s3fs threw away some function return values and returned
EIO instead.  This was due to not trusting the mix of -1 and errno
return codes.  Correct the obviously incorrect ones via visual
inspection.  Stronger typing may find more occurrences.  Fixes #1519.
2021-01-18 18:50:49 +09:00
a6563211af Update ChangeLog and configure.ac for 1.88 2021-01-11 17:59:28 +09:00
8d66b0e4a8 Updated ChangeLog for release 1.88 (#1514)
References #1511.
2021-01-05 16:46:41 +09:00
555c1dde3d Use Gtihub Actions instead of Travis CI 2021-01-04 23:46:54 +09:00
b04bca37a5 Add configuration for Chaos HTTP Proxy (#1508)
This can find errors in retry logic.  Chaos HTTP Proxy does not
support SSL bouncestorage/chaos-http-proxy#1 so users must set
s3proxy.endpoint and run via:

CHAOS_HTTP_PROXY=1 S3_URL=http://127.0.0.1:8080 make check -C test

It can also be helpful to increase retries and reduce sleep times.
References #1504.
2021-01-04 23:32:04 +09:00
168e588ac7 fix: Add reset offset (#1503) 2021-01-04 22:57:56 +09:00
7158e50ee2 Quote | and && to allow passing it to retry (#1506) 2021-01-04 22:28:40 +09:00
bd0fadbe5f Remove authorization header when remaking handle (#1505)
This avoids including Authorization in SignedHeaders.  s3fs will
recreate the Authorization header before sending the request.
2021-01-04 21:37:34 +09:00
d1c638ab7a fix 404 error message 2020-12-30 14:10:17 +09:00
51f65d7b14 fix: miss header when retry 2020-12-23 22:16:07 +09:00
a16d00d673 Simply curl_slist_sort_insert (#1494)
Some good taste from Linus:
https://github.com/mkirchner/linked-list-good-taste
Also avoid an allocation when replacing a value and tighten up tests.
2020-12-23 20:29:33 +09:00
4d0daddad4 Fixed about Github Actions failure(centos8 and macos) (#1498) 2020-12-23 19:34:04 +09:00
d246b9e8bf Update README for change in brew arguments
* Homebrew changed the arguments required to install casks. Previously,
  `brew cask install <package>` was the correct syntax, but now it's
  `brew install --cask <package>`. This small commit updates the
  instructions for installing `osxfuse` to reflect this change
2020-12-22 11:14:24 +09:00
ef3d4e506d Update README note on eventual consistency
AWS promise read-after-write consistency now, but presumably non-AWS S3-compatible services are still eventually consistent.
2020-12-15 08:50:53 +09:00
462b37b0bb Added Github Actions workflow 2020-12-05 22:57:40 +09:00
4341291cc2 Changed a condition of the atime test(fixed #1477) (#1487) 2020-12-03 02:45:05 +09:00
c589886ba5 Added a condition to the atime test (#1477) 2020-12-02 23:21:25 +09:00
d0363b118e Add tests for curl_util (#1481) 2020-11-24 21:37:09 +09:00
533322859d Added comment for nullPointerRedundantCheck/cppcheck2.2 2020-11-21 20:06:14 +09:00
f8d5b76edb Simplify handling of returned ETag (#1479)
This works around lifetime warnings uncovered by cppcheck.
References #1478.
2020-11-21 06:56:05 +09:00
834862f8a4 Add S3_ENDPOINT test variable (#1476) 2020-11-15 22:10:26 +09:00
d9f6469b7b Fixed flushing dirty data and compressed the cache size 2020-11-14 16:45:37 +09:00
852e6ee4c6 Fixed .gitignore for src/test_string_util.cpp 2020-11-14 16:22:30 +09:00
ecb24c9c26 Disable preprocessor warnings w/o optimizations (#1473)
This removes some fortify source warnings.  Also disable failing
memory sanitizer.
2020-11-09 21:48:07 +09:00
543231c9f2 Address warnings from clang-tidy 11 (#1470) 2020-11-09 21:15:20 +09:00
d96a08d4ad fixup! Implement AWS IMDSv2 support 2020-11-07 14:48:52 +09:00
f2f930300a Implement AWS IMDSv2 support
AWS IMDSv2 is a session oriented method for retrieving instance metadata,
including IAM credentials, in Amazon EC2.  It is enabled by default in
non-enforcing mode in AWS (meaning it retains backwards compatibility with
existing IMDSv1 clients), but can be switched to enforcing mode, in which
clients are required to return API tokens with requests.

With this change, we implement support for IMDSv2 and enable it by default when
IAM roles are our source for authentication credentials.  In the event that
s3fs is running in cloud environment offering an IMDSv1-compatible API, we
support graceful fallback to that mode.  It can also be selected explicitly via
the imdsv1only mount option.

More details on IMDSv2 are available at
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html
and
https://aws.amazon.com/blogs/security/defense-in-depth-open-firewalls-reverse-proxies-ssrf-vulnerabilities-ec2-instance-metadata-service/

Signed-off-by: Noah Meyerhans <nmeyerha@amazon.com>
2020-11-07 14:48:52 +09:00
81ad3ce0ae Fix directory authority 2020-11-07 14:47:53 +09:00
38e1eaa8a3 Added logfile option for non-syslog logging 2020-10-19 20:10:19 +09:00
6aa786b886 Flush dirty data after a writing a number of bytes (#1448)
This allows s3fs to write large files without consuming a large amount
of temporary local storage but can slow uploads due to server-side
copies.  References #617.  Fixed #1056.  Fixes #1257.
2020-10-13 22:30:42 +09:00
58750cc441 Fixed a bug that symlink could not be read after restarting s3fs 2020-10-11 22:14:36 +09:00
2188fb067e Merge pull request #1446 from gaul/use-cache/relative-path
Allow relative path with use_path
2020-10-10 23:13:07 +09:00
910255745e Allow relative path with use_path
Fixes #1161.
2020-10-10 18:13:23 +09:00
cf86fa51b0 Merge pull request #1441 from gaul/coverity
Suppress false positive from Coverity
2020-10-04 23:44:51 +09:00
a4e4ce8aea Merge pull request #1440 from gaul/test/undefined-behavior-sanitizer
Add memory and undefined behavior sanitizer
2020-10-04 23:19:36 +09:00
7f43b7fa53 Add memory and undefined behavior sanitizer
Remove Valgrind which duplicates the sanitizers and is much slower.
2020-10-04 22:55:27 +09:00
0492f75197 Merge pull request #1439 from gaul/run-once
Protect curl_warnings_once with a mutex
2020-10-04 22:43:56 +09:00
493cf20f95 Merge pull request #1435 from gaul/no-exceptions
Remove exceptions from s3fs_strtoofft
2020-10-04 22:19:25 +09:00
3553fb65a0 Suppress false positive from Coverity 2020-10-04 14:58:13 +09:00
059cc57ba6 Added atime and Corrected atime/mtime/ctime operations 2020-10-04 13:54:01 +09:00
4df4ffe06f Protect curl_warnings_once with a mutex
This allows ThreadSanitizer to run without warnings.
2020-10-03 21:09:35 +09:00
462347256d Changed the message level in the AutoFdEntity::GetFdEntity 2020-10-03 20:41:17 +09:00
133feb67c3 Merge pull request #1434 from gaul/const-string
Use const std::string& where possible
2020-10-03 10:02:03 +09:00
be308e9d11 Merge pull request #1436 from ggtakec/fix_code
Fixed signature error due to case of hex string
2020-10-03 03:44:49 +09:00
2cf195741c Fixed signature error due to case of hex string 2020-10-02 18:09:13 +00:00
f61baada46 Merge pull request #1433 from gaul/hex
Further simplify and centralize hex conversion
2020-10-03 00:34:02 +09:00
6e1e0d1d31 Merge pull request #1432 from gaul/v2-or-v4
Add sigv4 flag and fix v4 regression
2020-10-03 00:09:55 +09:00
66419e7292 Merge pull request #1431 from gaul/string/find_first_of
Prefer string::find_first_of(char) where possible
2020-10-02 23:42:17 +09:00
9e998877e9 Merge pull request #1430 from gaul/ostringstream
Simplify use of ostringstream
2020-10-02 23:26:41 +09:00
5ebd4039e6 Merge pull request #1426 from gaul/is_prefix
Call is_prefix instead of compare and substr
2020-10-02 23:03:10 +09:00
3628b9d1e2 Remove exceptions from s3fs_strtoofft
Explicit return codes are simpler and safer.
2020-10-02 22:53:12 +09:00
8d2bd874d7 Use const std::string& where possible
This hints to callers on usage.
2020-10-02 08:48:43 +09:00
7e27c6cf7d Further simplify and centralize hex conversion 2020-10-01 23:31:06 +09:00
b8ff4ede49 Sign GET requests with V4 signature correctly
This bug was previously masked by v2 fallback.  Fixes regression from
81805715bd.
2020-10-01 20:03:14 +09:00
081d6c1245 Allow setting signature V4-only
Default to allowing V2 or V4.
2020-10-01 20:03:14 +09:00
eb8004c355 Prefer string::find_first_of(char) where possible 2020-10-01 18:24:45 +09:00
b3bf9f8f54 Simplify use of ostringstream
Resetting this does not re-use the underlying buffer so creating a new
ostringstream has similar efficiency.
2020-10-01 17:55:34 +09:00
503c86bb8a Call is_prefix instead of compare and substr 2020-09-27 22:19:54 +09:00
757f4caee8 Merge pull request #1425 from gaul/create-bucket/sse
Do not send SSE headers during bucket creation
2020-09-27 11:34:15 +09:00
95fabd1f3a Merge pull request #1423 from gaul/nettle
Fix MD5 when using gnutls with nettle
2020-09-27 11:17:55 +09:00
0b42e08636 Merge pull request #1422 from gaul/c++/append-assign-at
Remove calls to append, assign, and at
2020-09-27 10:59:48 +09:00
d5e4f99e72 Merge pull request #1413 from liuyongqing/master
not call put headers if not exist pending meta
2020-09-27 10:37:22 +09:00
781d4dd857 Merge pull request #1424 from gaul/travis/ppc64
Disable builder for linux-ppc64le
2020-09-27 10:18:52 +09:00
f35fe850c0 Do not send SSE headers during bucket creation
This allows integration tests to pass with use_sse.
2020-09-26 13:25:18 +09:00
7102b9eb74 Disable builder for linux-ppc64le
This works around a travis-ci.com Java/S3Proxy incompatibility.  Also
fix vim formatting.  References #1415.
2020-09-25 23:25:36 +09:00
9a55c9fd9f Fix MD5 when using gnutls with nettle
This matches the non-nettle definition of s3fs_md5_fd.
2020-09-25 23:07:50 +09:00
041b4ec05c enforce exact key match in IBM IAM response 2020-09-25 22:41:19 +09:00
2438066d52 Remove calls to append, assign, and at
operator+, operator=, and operator[] are more idiomatic and consistent
with the code base.
2020-09-25 12:19:51 +09:00
3c5b35b3b9 Update README.md for migrating travis-ci.com 2020-09-21 18:59:45 +09:00
e98827ec6f not call put headers if not exist pending meta 2020-09-21 14:12:07 +08:00
864941d4d5 Merge pull request #1414 from gaul/clang-tidy/misc
Fix clang-tidy warnings
2020-09-21 07:49:59 +09:00
05863a3178 Fix clang-tidy warnings 2020-09-21 07:03:42 +09:00
075d161bb1 Merge pull request #1408 from gaul/env
Ensure environment variable is set when using ECS
2020-09-20 13:01:17 +09:00
f8b5c911ed Merge pull request #1407 from gaul/pid
Rework s3fs pid handling
2020-09-20 12:32:32 +09:00
6f40503328 Merge pull request #1406 from gaul/strcmp
Remove unnecessary calls to strcmp(str.c_str())
2020-09-20 11:28:41 +09:00
3440c3348c Merge pull request #1405 from gaul/is-prefix
Rename STR2NCMP to is_prefix for clarity
2020-09-20 10:03:53 +09:00
853be26612 Merge pull request #1404 from liuyongqing/master
fix dead lock in disk insufficient and optimize code
2020-09-20 01:34:02 +09:00
89b1c32b24 Rework s3fs pid handling
Previously S3FS_PID was not set in the correct shell and thus
ps u $S3FS_PID showed all programs.  This caused the flag detection to
fail when users ran other instances of s3fs with different flags.
References #1402.
2020-09-18 22:05:37 +09:00
44d2cc15f7 Ensure environment variable is set when using ECS
Previously s3fs crashed when AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
was not set.  References #1162.
2020-09-18 08:14:58 +09:00
76d88f2291 Merge pull request #1403 from gaul/vim/expandtab
Fix expandtab settings for tests
2020-09-17 21:35:58 +09:00
72340cfbd9 Merge pull request #1401 from gaul/test/hardlink
Add test for hardlink
2020-09-17 20:04:07 +09:00
81805715bd Remove unnecessary calls to strcmp(str.c_str()) 2020-09-17 20:00:45 +09:00
ebcbb02d16 Rename STR2NCMP to is_prefix for clarity
This may prevent confusion seen in
39ec8e242e.
2020-09-17 19:45:54 +09:00
8c29b60129 Merge pull request #1400 from gaul/test/concurrent-read
Add test for concurrent reads
2020-09-17 19:26:44 +09:00
93cf67c65d Merge pull request #1399 from gaul/md5-sha256
Use more descriptive names for digest functions
2020-09-17 17:11:19 +09:00
211cc0f5f2 fix dead lock in disk insufficient and optimize code 2020-09-16 22:45:28 +08:00
8fb70c5e4a Fix expandtab settings for tests
This matches the main source.
2020-09-15 22:11:14 +09:00
c58c91fc4f Merge pull request #1398 from gaul/memset
Remove unneeded memset calls
2020-09-15 22:09:54 +09:00
78e2345c19 Add test for hardlink 2020-09-15 22:07:25 +09:00
3bc565b986 Add test for concurrent reads 2020-09-15 21:25:51 +09:00
b7187352e1 Use more descriptive names for digest functions
Previously they used hex to refer to binary data which is confusing
since other std::string return types are actually hex.  Also remove
unused s3fs_md5sum.
2020-09-15 21:18:58 +09:00
1520ca6220 Merge pull request #1397 from gaul/hex
Centralize hex conversion
2020-09-15 21:14:23 +09:00
f7a63d5c97 Merge pull request #1396 from gaul/32-bit-read
Use off_t for read sizes
2020-09-15 20:05:19 +09:00
3958450c05 Added a class for automating fdentity reference counts 2020-09-14 22:02:28 +09:00
5121c73ed1 Remove unneeded memset calls
Also use constant for array lengths.
2020-09-14 19:51:36 +09:00
44eaac8471 Centralize hex conversion 2020-09-14 19:28:59 +09:00
77501c3600 Use off_t for read sizes
This fixes an issue with large multipart_size on 32-bit platforms like
Raspberry Pi.
2020-09-14 18:12:23 +09:00
8205607716 Fixed incorrect Signal related message at s3fs initialization and termination 2020-09-13 18:54:10 +09:00
c7132b7f56 Merge pull request #1390 from gaul/namespace-std
Remove uses of implicit namespace std
2020-09-13 13:26:22 +09:00
1043e08dfa Remove uses of implicit namespace std
Fixed via:

sed -i '/using namespace std/{N;d}' src/*.cpp
sed -i 's/ string/ std::string/g' src/*.cpp
sed -i 's/(string/(std::string/g' src/*.cpp
sed -i 's/\[string/\[std::string/g' src/*.cpp
sed -i 's/^string/std::string/g' src/*.cpp
sed -i 's/ ifstream/ std::ifstream/g' src/*.cpp
sed -i 's/ istringstream/ std::istringstream/g' src/*.cpp
sed -i 's/ ostringstream/ std::ostringstream/g' src/*.cpp
sed -i 's/ max(/ std::max(/g' src/*.cpp
sed -i 's/ min(/ std::min(/g' src/*.cpp
sed -i 's/ endl/ std::endl/g' src/*.cpp
2020-09-13 11:57:20 +09:00
e5f4f9b69e Merge pull request #1393 from gaul/32-bit-casting
Fix casting warnings on 32-bit platforms
2020-09-13 10:40:56 +09:00
1e3c10d803 Merge pull request #1392 from gaul/large-singlepart-32-bit
Use 64-bit off_t when computing digests
2020-09-13 10:39:34 +09:00
6fa4477673 Merge pull request #1389 from gaul/flags
Remove incorrect string prefix comparisons
2020-09-13 10:17:33 +09:00
6d1e704e34 Fix casting warnings on 32-bit platforms 2020-09-12 18:22:32 +09:00
ffc33a447f Use 64-bit off_t when computing digests
This allows 32-bit platforms like Raspberry Pi to upload single-part
objects larger than 2 GB.
2020-09-12 15:00:23 +09:00
39ec8e242e Remove incorrect string prefix comparisons
Previously flags like -o nouafoobar were parsed as -o noua.  Found
via:

grep STR2NCMP src/s3fs.cpp | grep -v '="'
2020-09-11 17:38:20 +09:00
0d4e39ad1c return 0 after parsing "use_session_token" arg (#1388)
return 0 after parsing "use_session_token" arg

I hope this might fix #651.

There's clearly an open bug in #651 confirmed by several users related to the parsing of the `-o use_session_token`. Looking at the source, I noticed that there was a return value everywhere except here, so I suspect this may be responsible.
2020-09-11 08:09:36 +09:00
6112eb6a49 Merge pull request #1385 from liuyongqing/master
close FdEntity to avoid leakage
2020-09-10 19:44:48 +09:00
986fab8738 close FdEntity to avoid leakage 2020-09-07 20:48:16 +08:00
b5ffd419d8 Source file division and set 4 spaces and cleanup 2020-08-26 17:43:50 +09:00
c6e23212bb Merge pull request #1375 from gaul/cppcheck
Add const where possible
2020-08-21 07:32:39 +09:00
e75c11956c Merge pull request #1374 from gaul/deep-archive
Add support for deep archive storage class
2020-08-21 07:01:43 +09:00
1ec8528502 Add const where possible
Found via cppcheck 2.1
2020-08-20 23:46:11 +09:00
892e7129c5 Add support for deep archive storage class 2020-08-20 23:42:45 +09:00
bdea2ee5c8 Merge pull request #1373 from gaul/enum
Use scoped enums for acl_t, sse_type_t, and storage_class_t
2020-08-20 23:06:52 +09:00
a5186c73c2 Merge pull request #1365 from ggtakec/check_lseek
Dynamically determine whether lseek extended options are supported
2020-08-20 22:36:56 +09:00
4580e6ff93 Merge pull request #1364 from ggtakec/test_nospace_mv
Added mv file test when disk space is insufficient
2020-08-20 22:08:09 +09:00
60d456a993 Use scoped enums for acl_t, sse_type_t, and storage_class_t
This prevents some kinds of implicit conversions.  Also deduplicate
str/from_str logic.  References #1371.
2020-08-20 18:46:18 +09:00
bcf6838e86 Merge pull request #1370 from gaul/vim/modeline
Correct vim modeline to 2-space indentation
2020-08-19 22:44:40 +09:00
41a66d9706 Merge pull request #1368 from gaul/curl-lock
Prefer named locks in curl
2020-08-19 22:17:32 +09:00
958ad83a4b Correct vim modeline to 2-space indentation 2020-08-19 21:03:46 +09:00
ba61470bae Prefer named locks in curl
This removes the confusing and unsafe pthread_mutex_t array.
2020-08-18 22:20:41 +09:00
0e895f60a0 Merge pull request #1366 from gaul/curl_handles_lock
Consistently lock curl_times and curl_progress
2020-08-17 19:27:21 +09:00
8210a1b2f2 Consistently lock curl_times and curl_progress
References #1362.
2020-08-17 09:47:38 +09:00
2feefeec47 Added mv file test when disk space is insufficient 2020-08-16 12:47:29 +00:00
55cb8920d5 Dynamically determine whether lseek extended options are supported 2020-08-16 12:37:11 +00:00
46acbf10ba Merge pull request #1363 from gaul/is-modified-race
Lock fdent_data_lock before accessing pagelist
2020-08-16 20:25:24 +09:00
f28e3bd89e Merge pull request #1362 from gaul/test/sanitizers
Add script to run tests using sanitizers
2020-08-16 19:15:05 +09:00
2c0408b95a Merge pull request #1357 from gaul/readdir
Call readdir instead of readdir_r
2020-08-16 18:50:38 +09:00
057da86d87 Merge pull request #1356 from gaul/printf-size_t
Prefer %zd and %zu for ssize_t and size_t
2020-08-16 18:16:59 +09:00
8de6cb3504 Lock fdent_data_lock before accessing pagelist
Found via ThreadSanitizer.  References #1353.  References #1362.
2020-08-16 17:44:03 +09:00
2bb745cdd7 Fixed a bug about move file over limit of ensure space 2020-08-16 17:42:20 +09:00
35090ba4d5 Call readdir instead of readdir_r
Only a single thread uses this directory stream.  Further, modern
implementations are thread-safe by default and deprecated this call:

https://man7.org/linux/man-pages/man3/readdir_r.3.html
2020-08-16 13:33:23 +09:00
132a1bebbb Prefer %zd and %zu for ssize_t and size_t
This removes unnecessary casting.
2020-08-15 17:30:23 +09:00
c8e13300e1 Add script to run tests using sanitizers
These currently show several kinds of errors.
2020-08-15 17:28:35 +09:00
a23d02923c add storage providers 2020-08-13 15:09:33 +09:00
194262c0ef Update ChangeLog and configure.ac for 1.87
Fixes #1335.
2020-08-10 11:52:14 +09:00
e2fbcb4d30 Merge pull request #1348 from gaul/readme/ibm
Move IBM information to Non Amazon S3 wiki page
2020-08-03 00:55:11 +09:00
0c1bc0f803 Add portability wrapper for stat(1)
Fixes #1344.
2020-08-02 23:14:58 +09:00
83361e7905 Add some code backticks to README 2020-08-02 23:02:11 +09:00
19abd9ffaf Move IBM information to Non Amazon S3 wiki page
This gives consistency with other providers:

https://github.com/s3fs-fuse/s3fs-fuse/wiki/Non-Amazon-S3
2020-08-01 20:22:30 +09:00
cbd925c56f Moved the SIGUSR2 handler to S3fsSignals class 2020-07-28 14:54:35 +09:00
63bbb47378 Merge pull request #1341 from gaul/stat-cache/default
Change default stat_cache_expire
2020-07-26 23:54:14 +09:00
0fbd0eac80 Change default stat_cache_expire
Previously s3fs cached files forever which confused users with
creating objects using another client.
2020-07-26 23:04:43 +09:00
e5231fa3c7 Merge pull request #1340 from gaul/test/external-directory
Test creating a directory with external program
2020-07-26 22:06:40 +09:00
ad1961417d Added SIGUSR1 option for cache file integrity test 2020-07-26 21:04:11 +09:00
4154e539ea Test creating a directory with external program
References #1264.
2020-07-25 21:22:53 +09:00
e0a38adaf6 Merge pull request #1333 from ggtakec/similar_processing
Put similar processing together into method GetCacheFileStatTopDir
2020-07-12 20:29:45 +09:00
c3e711da58 Merge pull request #1327 from pxeger/master
`s3fs#bucketname ... fuse` -> `bucketname ... fuse.s3fs` (#1321)
2020-07-12 19:14:27 +09:00
700e288718 Put similar processing together into method GetCacheFileStatTopDir 2020-07-12 08:12:02 +00:00
e72a64785b Merge pull request #1331 from gaul/travis/simplify
Simplify conditional statements
2020-07-12 12:52:21 +09:00
5ace2b70fc Simplify conditional statements 2020-07-10 19:34:46 +09:00
62c8be85d6 Interim fix for Travis macOS Build 2020-07-10 09:47:18 +09:00
3f6b5ae6a5 Merge pull request #1329 from gaul/cppcheck-2.1
Fix NULL pointer deference
2020-07-09 23:00:36 +09:00
dc365b65a0 Fix NULL pointer deference
Found via cppcheck 2.1.
2020-07-09 21:40:23 +09:00
9c88ec2128 Merge pull request #1326 from gaul/test/python2
Use Python 2 for write_multiple_offsets
2020-07-09 18:45:41 +09:00
3dd9832f61 s3fs#bucketname ... fuse -> bucketname ... fuse.s3fs (#1321) 2020-07-07 16:06:00 +01:00
4d1f5c899f Use Python 2 for write_multiple_offsets
This aligns with ut_test.py .  Using an older Python also allows
compatibility with the older macOS 10.12 Travis CI.  References #1323.
2020-07-07 21:12:52 +09:00
1f796d432d Fixed upload error about mixuploading sparse file and truncating file 2020-06-27 22:44:19 +09:00
35006e318f Fixed about ParallelMixMultipartUpload 2020-06-24 12:48:55 +09:00
7d0c66e08a Add support for glacier storage class.
Just a copy of what have been done in PR #271.
2020-06-23 11:23:21 +09:00
9dc4148743 Merge pull request #1312 from ggtakec/fix_bug_cache
Fixed a bug about serializing from cache file
2020-06-19 22:54:39 +09:00
f324d8e04f Fixed a bug about serializing from cache file 2020-06-19 12:57:27 +00:00
f16ee96d7e Merge pull request #1306 from gaul/http/500
Retry with exponential backoff during 500 error
2020-06-06 15:30:22 +09:00
0d849b38c2 Merge pull request #1305 from gaul/alibaba/multipart
Ignore case when comparing ETags
2020-06-06 15:05:39 +09:00
8ed020610f Merge pull request #1296 from gaul/test/oss
Import ossfs tests
2020-06-06 14:40:11 +09:00
d8766b2051 Retry with exponential backoff during 500 error
Amazon suggests retrying on both 500 and 503:

https://aws.amazon.com/premiumsupport/knowledge-center/http-5xx-errors-s3/

Fixes #1251.
2020-06-05 21:01:30 +09:00
9db70bab63 Ignore case when comparing ETags
This allows multipart upload to work with Alibaba OSS.
References #1297.
2020-06-05 18:17:52 +09:00
8a7548a9d4 Import ossfs tests
This turns up a failure in test_rename_file when calling seek(0) on a
renamed file.
2020-06-01 09:08:25 +09:00
0cb057dadd Merge pull request #1303 from gaul/rename/use_cache
Relink cache stats file atomically via rename
2020-06-01 00:10:33 +09:00
0f5db0d1bf Merge pull request #1302 from gaul/rename/nocopy
Fix renames of open files with nocopyapi option
2020-05-31 23:46:46 +09:00
94e67c9c58 Merge pull request #1301 from gaul/pthread-result
Check results from pthread mutex calls
2020-05-31 23:11:24 +09:00
274321524c Relink cache stats file atomically via rename
The new file may already exist so link may fail.  Further link/unlink
is not atomic.  Addresses an error when renaming an open with with
use_cache.  References #1296.
2020-05-31 23:09:58 +09:00
40f7007263 Check results from pthread mutex calls
Also remove some unnecessary exception handling.
2020-05-30 16:37:55 +09:00
66597ec5f2 Fix renames of open files with nocopyapi option
References #1296.
2020-05-30 15:45:43 +09:00
75e72385cc Added a parameter to output body to curldbg option 2020-05-25 08:49:01 +09:00
eb58460175 Merge pull request #1294 from gaul/test/profile
Allow overriding test credentials with a profile
2020-05-24 16:14:31 +09:00
0852521a7e Merge pull request #1293 from gaul/s3proxy
Update to S3Proxy 1.7.1
2020-05-24 15:22:00 +09:00
56ed6bb97f Merge pull request #1292 from gaul/retries
Do not allow zero retries
2020-05-24 15:03:03 +09:00
73098220bf Allow overriding test credentials with a profile 2020-05-24 12:05:16 +09:00
ca7756fa77 Update to S3Proxy 1.7.1
Release notes:

https://github.com/gaul/s3proxy/releases/tag/s3proxy-1.7.1
2020-05-23 10:06:44 +09:00
8b15db6dcb Do not allow zero retries
Retries actually means tries, e.g., if the user sets zero, s3fs will
never try an operation at all.
2020-05-23 10:05:23 +09:00
0b60aa81eb Merge pull request #1285 from ggtakec/wrapped_s3fs_strtoofft
Not abort process by exception threw from s3fs_strtoofft
2020-05-22 22:36:34 +09:00
da70cb92a8 Provide AWS CLI with correct test credentials
This allows tests to pass against real S3 implementations like
Backblaze.  References #272.
2020-05-22 19:27:18 +09:00
746a027e98 Expand on random write limitation 2020-05-05 08:12:04 +09:00
80c11b6c12 Not abort process by exception threw from s3fs_strtoofft 2020-05-03 13:46:05 +00:00
b76226a06d Merge pull request #1286 from gaul/gcs
Support Google Cloud Storage headers
2020-05-03 22:41:02 +09:00
8945e98d8b Support Google Cloud Storage headers
This allows s3fs to interpret objects created by gsutil.
2020-05-03 18:33:13 +09:00
97c249d5b9 Not abort process by exception threw from s3fs_strtoofft 2020-05-03 08:08:28 +00:00
6e134a23f9 Merge pull request #1280 from ggtakec/add_test_fdcache
Add test for cache file stat content
2020-05-03 16:33:50 +09:00
a4803543a1 Merge pull request #1282 from gaul/mime
Warn about missing MIME types instead of exiting
2020-05-03 15:15:05 +09:00
2cc88b933f Warn about missing MIME types instead of exiting
s3fs uses the MIME types file to set Content-Type for uploaded
objects.  Most distribution packages should install this via
recommended (not required) dependencies.  Users compiling from source
may not have this installed and s3fs should not prevent launching
since most users do not care about Content-Type.  Instead warn about
MIME types absence.  Fixes #1270.
2020-04-29 20:03:50 +09:00
ce1221c867 Add test for cache file stat content 2020-04-22 15:53:00 +00:00
005a684600 Fix typos 2020-04-22 21:49:11 +09:00
3af17c3019 Add test for out-of-order writes
References #1220.  References #1277.
2020-04-22 21:48:55 +09:00
f26a0aa71d Fixed insufficient upload size for mix multipart upload 2020-04-22 09:31:22 +09:00
2b4619842d Merge pull request #1278 from gaul/http-416
Add handler for HTTP 416
2020-04-21 22:38:54 +09:00
cf529e0af7 Add handler for HTTP 416
This prevents retries when the server indicates an unsatisfiable MPU
copy part request.  References #1220.
2020-04-21 19:45:10 +09:00
4da02d023b Improved strictness of cache file stats(file) 2020-04-21 19:45:03 +09:00
fe0677651e Merge pull request #1271 from ggtakec/fix_stat_file
Fixed the truncation bug of stat file for cache file
2020-04-19 16:27:11 +09:00
811ea0cb85 Fixed the truncation bug of stat file for cache file 2020-04-19 07:08:49 +00:00
a5f84535f3 Add install instructions for Arch Linux 2020-04-18 19:27:52 +09:00
84bf460f99 Remove deprecated sudo configuration
Addresses warnings of the form:

jobs.include: deprecated key sudo (The key `sudo` has no effect
anymore.)
2020-04-15 10:09:52 +09:00
538fbed302 Merge pull request #1266 from gaul/test/cache-eviction
Test cache eviction
2020-04-14 22:30:04 +09:00
feafb44bae Clean up macOS FUSE loading 2020-04-12 23:18:27 +09:00
a44fc1103d Avoid setting bogus group id
Addresses a symptom on newer macOS in Travis.
2020-04-12 22:37:22 +09:00
48a872e285 Address cppcheck 1.90 warning 2020-04-12 22:20:44 +09:00
c44a60f3f5 Fixed a bug of stats cache compression 2020-04-12 18:33:00 +09:00
f373df9682 Test cache eviction 2020-04-11 19:00:38 +09:00
9e01d5b8d1 Merge pull request #1254 from ggtakec/modify_mimetypes
Added mime option for strict checking of mime types file
2020-04-11 14:48:47 +09:00
7fbda230f5 Added mime option for strict checking of mime types file 2020-03-30 14:41:18 +00:00
56141557dc Avoid unneeded string copy
Found by clang-tidy 10.
2020-03-28 08:49:49 +09:00
fe2b269b6e Merge pull request #1253 from juliogonzalez/fix-1217
Generic compilation instructions: explain that /etc/mime.type is needed
2020-03-19 21:06:32 +09:00
eb6fe69af2 Generic compilation instructions: explain that /etc/mime.type is needed 2020-03-18 23:41:52 +01:00
6489c5d394 Merge pull request #1247 from ggtakec/fix_travis_timeout
Avoid TravisCI timeouts in test execution
2020-03-15 16:48:25 +09:00
854a8a8356 Avoid TravisCI timeouts in test execution 2020-02-24 09:56:18 +00:00
d34475d6a1 Add random writes and appends to README 2020-02-24 18:21:13 +09:00
b72f4b43a4 use correct content-type when complete multipart upload 2020-02-10 16:58:28 +09:00
34e797d6f5 Add Twitter link 2020-02-07 09:01:50 +09:00
bb20fc3c98 Update ChangeLog and configure.ac for 1.86
Fixes #1050.
2020-02-05 22:27:28 +09:00
3e66e42ae5 Merge pull request #1242 from ggtakec/bypass_test
Avoid test errors on MacOS
2020-02-05 01:29:11 +09:00
0665d78550 Temporary measure: reduce test time on MacOS 2020-02-04 15:38:19 +00:00
55d670f22f Change content-types test for MacOS 2020-02-04 14:51:50 +00:00
32ae0d2c79 Bypassed MacOS ensure_diskfree test 2020-02-04 14:00:47 +00:00
924eeb3587 Document host and servicepath
The various bits of host, url, and servicepath seem to overlap.
References #1203.
2020-02-04 21:13:29 +09:00
bc9126d774 Set directory MIME type to application/x-directory
Previously s3fs auto-detected the MIME type of directories like
"TOYOTA TRUCK 8.2.2" as application/x-troff-man.  This caused get_mode
to not set S_IFDIR which failed directory creation.  Instead force all
object names ending in / to application/x-directory.  Fixes #1183.
2020-02-04 20:03:21 +09:00
4df50e7f85 Test that s3fs automatically detects Content-Type
References #1217.
2020-02-04 19:47:09 +09:00
4e26728cbf break recursion when calling GetIAMCredentials (#1233)
break recursion when calling GetIAMCredentials
2020-01-31 16:48:37 +09:00
7135666060 Merge pull request #1234 from ggtakec/fix_dbg
Suppressed a lot of message output about cache cleanup
2020-01-31 01:00:46 +09:00
018ccb9a11 Suppressed a lot of message output about cache cleanup 2020-01-30 14:42:28 +00:00
ee1d3a9057 Merge pull request #1151 from liuyongqing/master
fix deadlock in clean up cache
2020-01-30 22:17:50 +09:00
b762a0a85b fix deadlock due to fdmanager_lock and fdent_data_lock 2020-01-29 12:03:53 +08:00
9771be29b2 Merge pull request #1232 from ggtakec/test_err_avoid
Not trap chown command errors directly
2020-01-28 20:47:54 +09:00
010a6b83ef Not trap chown command errors directly 2020-01-28 10:32:55 +00:00
87224b830b Merge pull request #1230 from ggtakec/fix_test
Fixed removing test file in integration-test-main.sh
2020-01-27 00:39:50 +09:00
9e77650e8c Fixed removing test file in integration-test-main.sh 2020-01-26 13:32:41 +00:00
e0712f444d Update source for clang-tidy 9.0.0 2020-01-13 20:56:45 +09:00
913b72fdaf Add intelligent_tiering to man page
Follows on to 39102608aa.
References #1219.
2020-01-13 20:26:01 +09:00
39102608aa Add intelligent tiering as option for storage class
Resolves Issue #1219
2020-01-13 20:24:35 +09:00
23945a0130 In memory cache for softlinks with cache out 2020-01-13 20:23:10 +09:00
bdfb9ee815 Document requester_pays option 2019-11-25 22:53:50 +09:00
1a75a94253 Merge pull request #1205 from mikelolasagasti/update-doc
Update install instructions for Debian and Fedora
2019-11-24 19:41:05 +09:00
a9d527d517 Merge pull request #1199 from ahuarte47/master_requester-pays
Adds requester_pays option to enable requests involving Requester Pays buckets
2019-11-24 17:44:34 +09:00
94666f7754 Merge pull request #1197 from bbxiao1/compilation-dependencies
Specfiy pkg-config as a necessary dependency for compilation
2019-11-24 13:28:25 +09:00
41acbaa746 Merge pull request #1200 from ggtakec/travis_cache_osx
Use travis cache for brew on osx
2019-11-24 12:47:31 +09:00
d5042a73bd Update install instructions for Debian and Fedora 2019-11-22 20:46:21 +01:00
f6756596b3 Use travis cache for brew on osx 2019-11-18 12:10:06 +00:00
a24f78f5a4 Adds requester_pays option to enable requests involving Requester Pays buckets 2019-11-18 12:38:16 +01:00
64d4b2c0b0 Specfiy pkg-config as a necessary dependency for compilation 2019-11-17 17:37:07 -07:00
cc4a307415 Add Gentoo install instructions 2019-11-05 03:44:07 +09:00
a07a5336f6 Merge pull request #1185 from bryceml/master
handle edge case when bucket name and first part of endpoint match
2019-10-31 23:42:47 +09:00
9789ca1a4d Merge pull request #1188 from gaul/s3proxy
Upgrade to S3Proxy 1.7.0
2019-10-31 23:00:35 +09:00
4ec2d685e7 Merge pull request #1181 from ggtakec/fix_1171
Fixed a rename bug
2019-10-31 22:36:34 +09:00
dc62953040 Upgrade to S3Proxy 1.7.0
Release notes:

https://github.com/gaul/s3proxy/releases/tag/s3proxy-1.7.0
2019-10-28 20:11:01 -07:00
0c42a74a8a handle edge case when bucket name and first part of endpoint match 2019-10-26 00:51:19 -06:00
cf3e82d10a Fixed a rename bug when enable_noobj_cache 2019-10-23 12:39:42 +00:00
0e815c2fbc Merge pull request #1173 from ggtakec/fixed_1171
Fixed test_write_multiple_offsets error on osx
2019-10-15 03:30:11 +09:00
27a5536749 Fixed test_write_multiple_offsets error on osx 2019-10-14 17:29:39 +00:00
db338b36b8 Merge pull request #1160 from gaul/mix_upload
Add test for writing to multiple offsets
2019-10-14 22:07:50 +09:00
72b906255f Merge pull request #1169 from ggtakec/test_brew
Updated .travis.yml for tapping homebrew/cask-cask
2019-10-14 21:38:10 +09:00
2211678d91 Updated .travis.yml for tapping homebrew/cask-cask 2019-10-14 11:44:06 +00:00
80162c126b Add test for writing to multiple offsets
References #1098.
2019-09-25 19:31:08 -07:00
1db94a0b30 Fixed to use copy api in multipart upload 2019-09-25 19:30:58 -07:00
b6349e9428 Merge pull request #1158 from ggtakec/fix_cppcheck
Fixed build error by cppcheck 1.89
2019-09-23 20:22:33 +09:00
bedd648d47 Fixed build error by cppcheck 1.89 2019-09-23 10:49:49 +00:00
58b3cce320 Merge pull request #1066 from gaul/sign-requests
Sign request immediately before sending
2019-09-23 15:58:21 +09:00
81102a5963 Merge pull request #1149 from ggtakec/fix_retry
Fixed a bug that type and op are not inherited
2019-09-08 20:32:43 +09:00
42fb30852b Merge pull request #1145 from gaul/bool
Fix a few bool types
2019-09-08 20:04:30 +09:00
e51361cb94 Merge pull request #1143 from gaul/doc/umask
Document umask flag
2019-09-08 19:49:58 +09:00
80a9ed9d6a Merge pull request #1142 from gaul/base
Expose base parameter in s3fs_strtoofft
2019-09-08 19:31:31 +09:00
e2129001eb Fixed a bug that type and op are not inherited 2019-09-08 09:59:04 +00:00
805cc064af Fix a few bool types
Found via clang-tidy.
2019-09-05 10:42:42 -07:00
3c2279db39 Document umask flag 2019-09-04 20:53:58 -07:00
412876ca33 Expose base parameter in s3fs_strtoofft
This fixes a regression from ccf3e7bfa2
which caused the misparsing of octal inputs for the mp_umask and umask
flags.  It also allows some callers to be more precise about their
decimal inputs.
2019-09-04 20:41:47 -07:00
461a346bf4 Sign request immediately before sending
Previously s3fs could create a long list of pre-signed requests which
could take longer than the default S3 clock skew limit of 15 minutes.
This also changes SHA-256 computation from single- to multi-threaded
since this is now computed in the worker threads.  Regression from
88cd8feb05.  Fixes #1019.
2019-08-29 15:35:27 -07:00
ae4bcd405c use correct content-type when overwriting and copying files 2019-08-28 22:25:09 -07:00
0536dc1112 Refixed strict processing of MultiRead method 2019-08-25 20:46:01 -07:00
1c3507ede1 Merge pull request #1135 from gaul/curl-timeout
Remove useless CURLE_OPERATION_TIMEDOUT check
2019-08-25 17:53:02 +09:00
3f47037cc7 Merge pull request #1134 from gaul/test/size
Verify file size via metadata as well as data
2019-08-25 17:34:41 +09:00
d87321ef3c Merge pull request #1133 from gaul/default-acl
Promote default ACL to enum
2019-08-25 17:05:54 +09:00
01ac815346 Remove useless CURLE_OPERATION_TIMEDOUT check
CheckBucket only returns errno and HTTP status codes.
2019-08-20 18:44:48 -07:00
2daa1d53d9 Verify file size via metadata as well as data 2019-08-20 18:36:44 -07:00
cc2eed84a5 Promote default ACL to enum
This sanity checks ACLs during initialization and also omits sending
the header when set to PRIVATE which is the default.
2019-08-20 15:05:58 -07:00
c644e4bef2 Merge pull request #1131 from ggtakec/fix_typo
Fixed typo in #1129
2019-08-14 22:26:04 +09:00
a7d83df3eb Fixed typo in #1129 2019-08-14 12:39:38 +00:00
e1886b5343 Merge pull request #1130 from ggtakec/update_multiread
Strict processing of MultiRead method
2019-08-14 00:38:59 +09:00
873e376098 Strict processing of MultiRead method 2019-08-13 15:23:13 +00:00
3c378a4a7a Merge pull request #1129 from ggtakec/update_test
Modified the test script a little
2019-08-13 23:55:17 +09:00
ca7266fb76 Modified the test script a little 2019-08-13 14:21:42 +00:00
4a0c23258e Fixed MultiRead method to exit after waiting other parts at error 2019-08-12 14:45:06 -07:00
ccc79ec139 Merge pull request #1126 from ggtakec/fix_multipart_copy_retry
Fixed multipart copy and its retry handler
2019-08-12 01:50:44 +09:00
5c4a0a862a Fixed multipart copy and its retry handler 2019-08-11 16:21:26 +00:00
2a779df4fd Merge pull request #1125 from ggtakec/fix_nocopyapi_copy
Fixed simple copy with nocpoyapi and modify flag in fdcache
2019-08-11 17:30:04 +09:00
f5bf41cf11 Fixed simple copy with nocpoyapi and modify flag in fdcache 2019-08-11 07:42:48 +00:00
f74c7407db Merge pull request #1118 from gaul/atoi
Prefer s3fs_strtoofft over atoi and strtol
2019-08-06 21:23:37 +09:00
433c04af26 Merge pull request #1116 from gaul/bodydata
Do not heap allocate BodyData
2019-08-06 21:08:02 +09:00
2e51a339a9 Merge pull request #1115 from gaul/hash-length
Use length from s3fs_HMAC256 for consistency
2019-08-06 20:49:22 +09:00
0411872dda Merge pull request #1121 from ggtakec/update_test
Added stats cache expire option for test
2019-08-06 20:32:48 +09:00
d8f1aef7be Added stats cache expire option for test 2019-08-06 10:55:38 +00:00
14d3e12103 Merge pull request #1114 from gaul/flush/return-value
Consume return value from FdEntity::Flush
2019-08-06 14:12:25 +09:00
fd13eb314b Merge pull request #1120 from ggtakec/osx_auto_cache
Added auto_cache option for test on osx
2019-08-06 13:31:23 +09:00
daba563a1c Added auto_cache option for test on osx 2019-08-06 02:44:18 +00:00
b79b0b1a92 Merge pull request #1119 from ggtakec/osx_direct_io
Added direct_io option for test on osx
2019-08-06 11:14:51 +09:00
01d4323b50 Merge pull request #1117 from gaul/retry
Increase test startup retries on Linux
2019-08-06 10:54:55 +09:00
dc85eda188 Added direct_io option for test on osx 2019-08-05 17:12:49 +00:00
ccf3e7bfa2 Prefer s3fs_strtoofft over atoi and strtol
The former propagates errors consistently.
2019-08-03 16:13:48 -07:00
d22acae9a3 Increase test startup retries on Linux
This matches the number of retries on macOS and allows Valgrind to
work.
2019-08-03 16:10:42 -07:00
7ecfba811e Do not heap allocate BodyData
Callers already manage lifetimes via Clear().
2019-08-03 15:50:46 -07:00
1e7330e499 Merge pull request #1113 from gaul/unused
Remove unused field
2019-08-04 01:31:56 +09:00
68475e5fcf Merge pull request #1112 from gaul/travis/macos
Upgrade to Xcode 9.2
2019-08-04 01:15:18 +09:00
8cc008c501 Merge pull request #1111 from gaul/test/read-external-object
Add test to read an externally created object
2019-08-03 22:36:34 +09:00
faaaf2ee3c Merge pull request #1110 from gaul/flags/noobj
Test enable_noobj_cache
2019-08-03 22:24:56 +09:00
3d42d0515d Merge pull request #1109 from gaul/lock-already-held
Pass lock_already_held state to DelStat
2019-08-03 22:13:22 +09:00
3d70e8966f Merge pull request #1108 from gaul/lock/diskspace
Always hold lock when accessing free_disk_space
2019-08-03 22:01:31 +09:00
6837cbfe06 Merge pull request #1107 from gaul/concurrency
Access FdEntity metadata while holding fdent_lock
2019-08-03 21:49:54 +09:00
a5c20175a1 Use length from s3fs_HMAC256 for consistency
EVP_MAX_MD_SIZE can range up to 64.  Found by Coverity.
2019-08-02 10:40:55 -07:00
43d1439420 Consume return value from FdEntity::Flush
Found via Coverity.
2019-08-02 10:01:06 -07:00
d8cf26bd50 Remove unused field
Found via clang.
2019-08-01 16:42:38 -07:00
c321c8c23f Add test to read an externally created object
References #890.
2019-08-01 16:12:51 -07:00
6227fce091 Upgrade to Xcode 9.2
This is the latest version supported by macOS 10.12.
2019-08-01 15:50:50 -07:00
aba8e6ccfa Test enable_noobj_cache 2019-08-01 12:39:11 -07:00
f528a86219 Pass lock_already_held state to DelStat 2019-08-01 11:07:56 -07:00
5b15c7c4e9 Always hold lock when accessing free_disk_space
Slightly reorder locks to avoid double locking.  Found via
ThreadSanitizer.
2019-07-30 08:36:54 -07:00
afd438d363 Access FdEntity metadata while holding fdent_lock
Create copies to avoid thread races.  Found via ThreadSanitizer.
Follows on to ecf13a8cb9.
2019-07-29 13:54:57 -07:00
80972aa33d Merge pull request #1106 from ggtakec/fix_filter
Fixed filter-suite-log.sh for on osx
2019-07-22 18:13:07 +09:00
520995a7e8 Merge pull request #1104 from gaul/sysconf
Eagerly initialize sysconf variables
2019-07-22 18:04:39 +09:00
5c3c6bff2f Fixed filter-suite-log.sh for on osx 2019-07-21 15:32:10 +00:00
fb937635f5 Eagerly initialize sysconf variables
Previously s3fs had races updating these shared variables.  Found via
ThreadSanitizer.
2019-07-17 09:08:13 -07:00
3ad1c95e86 Merge pull request #1103 from gaul/config/readwrite-timeout
Use consistent default for readwrite_timeout
2019-07-17 22:37:02 +09:00
2c4c78fd65 Merge pull request #1102 from gaul/test/concurrent-write
Add a test for concurrent writes
2019-07-17 22:24:45 +09:00
0afef077ed Merge pull request #1101 from gaul/gmtime
Avoid race when using thread-unsafe gmtime
2019-07-17 22:17:18 +09:00
80f598f439 Merge pull request #1099 from ggtakec/filter_log
Add log output filter script at test failure
2019-07-17 22:01:28 +09:00
bacd15714a Use consistent default for readwrite_timeout
Previously curl threads mutated this shared state without a lock.
Found via ThreadSanitizer.
2019-07-16 22:03:56 -07:00
5cb7a31c09 Add a test for concurrent writes 2019-07-16 21:57:43 -07:00
99aace4fc9 Avoid race when using thread-unsafe gmtime
Found via ThreadSanitizer.
2019-07-16 07:28:34 -07:00
c7f8f61d09 Change test_concurrency test 2019-07-15 15:58:54 -07:00
159cd2c682 Add log output filter script at test failure 2019-07-15 06:37:43 +00:00
513f41fddf Merge pull request #1097 from ggtakec/fix_lock
Add Lock() func parameter in RowFlush()
2019-07-15 11:56:21 +09:00
543aed2a32 Merge pull request #1096 from gaul/pthread/lock-checking
Expand error checking to all pthread_mutex_t
2019-07-15 11:43:56 +09:00
20ea96328c Merge pull request #1095 from gaul/intmax_t
Avoid narrowing time_t and off_t args in logging
2019-07-15 11:33:44 +09:00
007edb1773 Merge pull request #1090 from gaul/strtoofft
Implement s3fs_strtoofft via strtoll
2019-07-15 11:26:03 +09:00
f78bcc5229 Add Lock() func parameter in RowFlush() 2019-07-15 01:52:29 +00:00
43ec064fb9 Expand error checking to all pthread_mutex_t 2019-07-14 18:21:23 -07:00
ffac4c8417 Avoid narrowing time_t and off_t args in logging
This displays correct results on 32-bit platforms.
2019-07-14 17:02:36 -07:00
4adcd4a6c8 Implement s3fs_strtoofft via strtoll
This tightens error checking and aligns s3fs with known good behavior.
2019-07-14 15:15:06 -07:00
e936854493 Merge pull request #1094 from larsch/master
Fix multipart upload not setting curl options
2019-07-15 05:13:37 +09:00
850a813171 Merge pull request #1092 from liuyongqing/master
fix coredump caused by fd_manager_lock locking
2019-07-15 04:53:10 +09:00
5bbcd3b981 Merge pull request #1089 from gaul/null-dereference
Avoid null dereference
2019-07-15 04:17:10 +09:00
a337c32840 Merge pull request #1088 from gaul/clang-tidy/misplaced-const
Avoid misplaced const via removing unneeded typedef
2019-07-15 04:08:51 +09:00
d39e4e4b1f Merge pull request #1087 from gaul/clang-tidy/deprecated-headers
Prefer modern C headers
2019-07-15 03:50:15 +09:00
b51d60ef5e Merge pull request #1082 from gaul/locking/fixes
Add a missing lock to SetCtime
2019-07-15 03:38:53 +09:00
58037da061 Fix multipart upload not setting curl options 2019-07-14 14:09:37 +02:00
1eb266588e Add a missing lock to SetCtime
Also lock before log statements which touch member variables.
2019-07-13 17:53:38 -07:00
deb560067e Merge pull request #1085 from gaul/no-recusive-locks
Remove recursive locking
2019-07-14 01:14:32 +09:00
4e351c59e3 fix coredump caused by fd_manager_lock locking 2019-07-13 12:03:27 +08:00
eb597289cb Avoid null dereference
Found via clang-tidy.
2019-07-12 18:40:24 -07:00
6fd42d9fe4 Prefer modern C headers
Found and fixed via clang-tidy.
2019-07-12 03:50:59 -07:00
efff9c01a6 Avoid misplaced const via removing unneeded typedef
Found via clang-tidy.
2019-07-12 03:41:19 -07:00
a83d5baa90 Remove recursive locking
Recursive locking is frowned upon and is incompatible with
PTHREAD_MUTEX_ERRORCHECK.  Also clean up pthread_mutex_lock error
checking.
2019-07-10 12:39:00 -07:00
50d13255e4 Merge pull request #1081 from gaul/write-blocks-readdir
Break FdEntity locks into data and metadata
2019-07-11 03:40:26 +09:00
5195fa93fa Merge pull request #1071 from gaul/macos/xattr
Run xattr tests on macOS
2019-07-07 17:37:00 +09:00
e5e63d6ac3 Merge pull request #1067 from gaul/mismatched-free
Fix mismatched new[]/free
2019-07-07 16:55:07 +09:00
7a65a414c3 Merge pull request #1080 from gaul/xml/simplification
Add simple XML parsing wrapper
2019-07-07 16:44:18 +09:00
4a192ffdf9 Run xattr tests on macOS 2019-07-07 00:39:45 -07:00
944d21cabb Fix mismatched new[]/free
Found via Valgrind.
2019-07-07 00:36:48 -07:00
d267212289 Merge pull request #1079 from gaul/cppcheck/shadowing
Avoid shadowing variable in FdEntity::Open
2019-07-07 16:29:42 +09:00
58d8e5586a Merge pull request #1078 from gaul/multipart/2x
Issue multipart when object size exceeds part size
2019-07-07 16:21:22 +09:00
ce803daf4a Merge pull request #1077 from gaul/openssl/locking
Annotate OpenSSL locking functions as unused
2019-07-07 16:10:14 +09:00
9bf34e2fda Merge pull request #1076 from gaul/doc/man-help
Add documentation for use_session_token and use_rrs
2019-07-07 15:45:42 +09:00
52218d2ddb Merge pull request #1075 from gaul/fortify-source
Compile with FORTIFY_SOURCE
2019-07-07 15:38:08 +09:00
6bd1a7eac0 Merge pull request #1074 from gaul/clang-tidy
Configure clang-tidy target
2019-07-07 15:28:08 +09:00
6177d7b096 Merge pull request #1073 from gaul/deps/s3proxy
Upgrade to S3Proxy 1.6.2
2019-07-07 15:19:00 +09:00
3161bf4608 Merge pull request #1070 from gaul/bash/nounset
Prohibit pipeline failures
2019-07-07 15:10:53 +09:00
2349dafb98 Merge pull request #1069 from gaul/macos/sed
Use system sed on macOS
2019-07-07 15:00:48 +09:00
1cd58d7828 Merge pull request #1035 from gaul/test/flags
Individually test multiple s3fs flags
2019-07-07 14:41:15 +09:00
8aa06d621a Add documentation for use_session_token and use_rrs
Fixes #929.
2019-07-06 10:04:43 -07:00
ecf13a8cb9 Break FdEntity locks into data and metadata
Previously long-running data operations like RowFlush would block
metadata operations like GetStats and thus user readdir.  Fixes #928.
2019-07-05 23:12:24 -07:00
b8ff6a647e Add simple XML parsing wrapper
Also simplify check_region_error.
2019-07-05 17:39:09 -07:00
49110c671d Avoid shadowing variable in FdEntity::Open
Found via cppcheck 1.88.
2019-07-05 15:06:18 -07:00
febaf6849f Issue multipart when object size exceeds part size
Previously s3fs issued multipart uploads when the object size was
twice the part size.  Conjoining this with the part size was confusing
and s3fs should add a separate tunable for this if needed, similar to
singlepart_copy_limit.  Fixes #1058.
2019-07-05 12:14:56 -07:00
4893174652 Annotate OpenSSL locking functions as unused
OpenSSL 1.1.0 removed these and generates warnings with newer
versions.
2019-07-05 10:45:57 -07:00
5820c72092 Compile with FORTIFY_SOURCE
This can catch some classes of buffer overflows.
2019-07-04 10:20:26 -07:00
4f23f38583 Individually test multiple s3fs flags
Remove unneeded comments; single part limits ensure that the tests
exercise multipart code paths even with smaller files.
References #971.
2019-07-03 21:09:40 -07:00
bbfa91141a Configure clang-tidy target
Also fix nits.
2019-07-03 14:04:11 -07:00
f439c6382f Upgrade to S3Proxy 1.6.2
Notably this includes support for List Objects v2 which AWS CLI uses.
Release notes:

https://github.com/gaul/s3proxy/releases/tag/s3proxy-1.6.2
2019-07-03 10:37:26 -07:00
21321a9d96 Merge pull request #1065 from gaul/doc/ssl-verify-hostname
Document ssl_verify_hostname
2019-07-03 22:15:33 +09:00
f03b50fd13 Merge pull request #1063 from gaul/truncate-2nd-open-fd
Flush file when opening second fd
2019-07-03 21:14:03 +09:00
15a870f9d9 Merge pull request #1061 from gaul/fdpagelist/value
Make fdpage a value type in fdpage_list_t
2019-07-03 21:04:16 +09:00
9472ee4a01 Prohibit pipeline failures 2019-07-03 02:57:40 -07:00
1f1f824da7 Use system sed on macOS
This requires fewer developer customizations to work on macOS.
Requires some GNU workarounds.
2019-07-02 22:17:02 -07:00
f02105c346 Document ssl_verify_hostname
References #1064.
2019-07-02 10:26:29 -07:00
c596441f58 Flush file when opening second fd
Previously when s3fs had dirty local data and an application opened a
second fd it would remove the stat cache entry, query S3 for the size
which was still zero, then reinitialize FdEntry with this incorrect
size.  Instead flush local data to S3 so this query works.  It is
possible that a more involved patch could do this with a less
heavyweight approach but this requires changing open.  This does not
completely fix git clone but allows it to proceed further.  Also make
some cache methods const-correct.  References #839.
2019-07-02 01:12:09 -07:00
455e29cbea Make fdpage a value type in fdpage_list_t
This simplifies memory management.
2019-07-01 09:30:48 -07:00
511d223468 Merge pull request #1059 from gaul/casting
Fix casting warning on 32-bit
2019-07-01 22:26:14 +09:00
5324c1b588 Merge pull request #1055 from gaul/test/litter
Remove litter from test_concurrency
2019-07-01 22:10:57 +09:00
554ea49294 Merge pull request #1051 from gaul/log/flags
Log flags as hexadecimal
2019-07-01 21:36:17 +09:00
d7f77a6282 Fix casting warning on 32-bit 2019-06-29 20:57:42 -07:00
048aea1151 Remove litter from test_concurrency 2019-06-26 20:29:27 -07:00
f1ad626b46 Log flags as hexadecimal 2019-06-24 16:13:07 -07:00
a78d8d1da4 Merge pull request #1049 from gaul/external-modication
Remove cache file when object time differs
2019-06-24 00:51:54 +09:00
fbebc6fa57 Merge pull request #1048 from gaul/log/curl
Emit older curl warnings only once
2019-06-24 00:42:44 +09:00
c18fc901c4 Merge pull request #1045 from gaul/test/umount-s3fs
Correct macOS integration test umount
2019-06-23 23:02:46 +09:00
245f14c8c1 Merge pull request #1041 from gaul/doc/typo
Fix singlepart_copy_limit default
2019-06-23 22:57:43 +09:00
d732eef776 Merge pull request #1039 from gaul/off_t
Convert file offsets from size_t to off_t
2019-06-23 22:51:04 +09:00
56b184fd0c Merge pull request #1032 from gaul/man/env
Add environment variables to man page
2019-06-23 22:42:39 +09:00
9e5eaad79b Remove cache file when object time differs
Check the modification times to determine whether an object has
updated.  This relies on low clock skew between s3fs and the S3
server; a more robust approach could use the ETag.  Fixes #1047.
2019-06-22 19:09:00 -07:00
738eaadcbf Emit older curl warnings only once
This makes Travis logs actually readable.
2019-06-22 10:01:20 -07:00
1cf3d2452e Correct macOS integration test umount
Previously errexit could prevent this from succeeding.
2019-06-19 11:01:32 -07:00
670dce6f4a Merge pull request #1036 from gaul/travis/macos
Do not update Homebrew in macOS builder
2019-06-18 22:24:36 +09:00
07cfdcf205 Fix singlepart_copy_limit default
Follows on to c5ebf5d328.
2019-06-15 17:38:14 -07:00
15b7450713 Convert file offsets from size_t to off_t
The latter is 64-bits on 32-bit platforms when specifying
-D_FILE_OFFSET_BITS=64.  This allows early Raspberry Pis to use files
larger than 2 GB.  It also cleans up some ugly casting.  Fixes #620.
Fixes #656.
2019-06-15 17:05:37 -07:00
272e0d3d46 Do not update Homebrew in macOS builder
This takes 5 minutes to run and can cause Travis timeouts.
References #1035.
2019-06-12 18:17:56 -07:00
8d8a2a66e5 Add environment variables to man page
Also fix typo in AWS credentials.
2019-05-15 18:49:18 +07:00
befc2e9e6f Merge pull request #1025 from gaul/nocopyapi
Update ctime during nocopyapi operations
2019-05-02 17:55:42 +09:00
059ab1f0f4 Update ctime during nocopyapi operations
Follows on to 2c43b1e12b.  Fixes #971.
2019-04-30 18:59:51 +09:00
f2fe1738cd Merge pull request #1021 from michallula/master
fix issue with aws session token provided inside ~/.aws/credentials file
2019-04-28 11:03:48 +09:00
0d4847596e fix issue with aws session token provided inside ~/.aws/credentials file 2019-04-25 14:29:35 +02:00
8e86ef1634 Merge pull request #1015 from gaul/c++03
Remove uses of std::map::at
2019-04-22 23:01:29 +09:00
a32a05962e Merge pull request #1014 from gaul/macro
Prefer simple over compound statements in macros
2019-04-22 22:49:23 +09:00
a7e81fda9b Merge pull request #1012 from gaul/doc/markdown
Address markdownlint warnings
2019-04-22 22:39:55 +09:00
9e4f9d4bdc Remove uses of std::map::at
This provides compatibility with C++03 and removes duplicate lookups.
2019-04-18 16:06:59 +09:00
0677a096a9 Prefer simple over compound statements in macros
This prohibits missing semicolons.
2019-04-17 21:46:24 +09:00
381835e2a9 Merge pull request #1008 from michallula/master
AWS session token support
2019-04-17 17:52:08 +09:00
af070fa3de Address markdownlint warnings 2019-04-17 08:09:31 +09:00
f9cd43b684 add session token support 2019-04-16 16:53:05 +02:00
7095787f1f Merge pull request #1011 from gaul/doc/man
Make man page and --help more consistent
2019-04-16 23:07:17 +09:00
4ca336aed0 Merge pull request #1003 from gaul/doc/installation
Standardize installation section
2019-04-16 22:30:51 +09:00
8a18806a57 Make man page and --help more consistent
Mostly small fixes but also some reordering.  References #929.  Found
via:

diff -u <(man --no-hyphenation doc/man/s3fs.1 | tr -s ' ' '\n' | sed '/^-o$/d' ) <(src/s3fs --help | tr -s ' ' '\n' | sed '/^-$/d')
2019-04-14 14:34:24 +09:00
e5e124b9aa Merge pull request #1006 from gaul/shellcheck
Address shellcheck errors
2019-04-09 23:39:11 +09:00
090ac7a8a0 Merge pull request #1005 from gaul/travis/simplify
Remove custom cppcheck from ppc64le Travis config
2019-04-09 23:29:06 +09:00
97af471aa6 Remove custom cppcheck from ppc64le Travis config 2019-04-09 21:25:58 +09:00
0176fc712b Address shellcheck errors 2019-04-09 21:11:31 +09:00
c426c896d0 Standardize installation section
Sort Linux distributions and simplify/standardize grammar.
2019-04-09 07:52:54 +09:00
0a99470369 Merge pull request #1002 from gaul/sse-c
Correctly calculate MD5 hash for SSE-C keys
2019-04-09 00:17:12 +09:00
cd280d8702 Merge pull request #1001 from gaul/missing-braces
Add missing braces
2019-04-08 23:55:02 +09:00
b1bade37d8 Merge pull request #1000 from ggtakec/master
Modified to discard _netdev option etc
2019-04-08 23:43:02 +09:00
005c186e1b Merge pull request #998 from gaul/doc/compilation
Move compilation instructions to separate file
2019-04-08 23:32:54 +09:00
6f8ecb28c5 Correctly calculate MD5 hash for SSE-C keys
Previously s3fs calculated the strlen of a binary input instead of
using the stored length.  This yielded IO errors when interacting with
SSE-encrypted objects.  Fixes #696.
2019-04-08 21:49:42 +09:00
4c28eb2a78 Move compilation instructions to separate file
Most users should use distribution packages and expert users can
consult this file.  References #991.
2019-04-08 15:56:46 +09:00
042332bcec Add missing braces
Found via clang-tidy.  Also fix errant indentation.
2019-04-07 23:12:27 +09:00
071cd0f849 Modified to discard _netdev option etc 2019-04-07 11:51:55 +00:00
d7bb834bcb Merge pull request #999 from gaul/malloc
Prefer new over malloc
2019-04-07 20:21:58 +09:00
9b437fc1fe Merge pull request #997 from gaul/doc/http
Prefer HTTPS links in documentation where possible
2019-04-07 19:44:38 +09:00
6f6a67807b Prefer new over malloc
The former cannot return NULL and will allow use of scoped pointers.
2019-04-07 16:54:24 +09:00
e5785d4690 Prefer HTTPS links in documentation where possible
This also corrects a test URL which was HTTPS in practice.
2019-04-05 17:31:06 +09:00
a4ce54d615 Merge pull request #995 from jaygooby/master
Work with filenames that include spaces
2019-04-02 23:17:39 +09:00
ddbcec5c96 Work with filenames that include spaces
• Simplified the stat generation line (single exec using only stat)
• Quote variables so that the cache directory can also include spaces
• while/read loop to handle spaces in cached files
  (IFS was causing problems when all the files were saved into a single variable)
2019-04-02 10:35:25 +01:00
7cbb4c958b Merge pull request #994 from gaul/doc/nits
Add commas to see also
2019-03-31 07:27:44 +09:00
6c5adbb9af Add commas to see also 2019-03-30 23:25:58 +09:00
4db6e1a10a Merge pull request #993 from ggtakec/test
Fixed a bug about overwrite metadata at updating directory stats
2019-03-30 01:18:48 +09:00
ea517c80a4 Fixed a bug about overwrite metadata at updating directory stats 2019-03-29 15:30:30 +00:00
9f6ed6c08e Merge pull request #992 from ggtakec/master
Added see also section to man page
2019-03-29 09:23:18 +09:00
b1ddb483a4 Added see also section to man page 2019-03-28 23:59:19 +00:00
17352ef4fd Merge pull request #987 from ggtakec/master
Support undefined CURLoption in libcurl library used in build
2019-03-22 20:34:48 +09:00
71766039ff Support undefined CURLoption in libcurl library used in build 2019-03-22 10:47:42 +00:00
c607c9be58 Merge pull request #985 from ggtakec/master
Fixed configure.ac about abuses AC_CHECK_FILE
2019-03-22 15:19:04 +09:00
df604e50fb Fixed configure.ac about abuses AC_CHECK_FILE 2019-03-22 05:22:23 +00:00
876662ff89 Merge pull request #982 from gaul/cppcheck/find-first-of
Simplify string comparison
2019-03-22 13:59:45 +09:00
058706014b Simplify string comparison
Found via newer cppcheck.
2019-03-14 22:19:33 +09:00
99ec09f13a Merge pull request #978 from ggtakec/master
Updated ChangeLog and configure.ac etc for release 1.85
2019-03-11 21:32:25 +09:00
4a011d87e0 Updated ChangeLog and configure.ac etc for release 1.85 2019-03-11 11:53:57 +00:00
c6edc2cd8f Merge pull request #977 from gaul/readme/homebrew
Make macOS instructions consistent with others
2019-03-11 20:26:26 +09:00
cc196bfdf0 Make macOS instructions consistent with others 2019-03-11 14:36:36 +09:00
895d5006bb Merge pull request #975 from ggtakec/master
Fixed ref-count when error occurred.
2019-03-10 15:09:09 +09:00
62dcda6a56 Fixed ref-count when error occurred. 2019-03-10 06:04:19 +00:00
cbf072bc55 Merge pull request #967 from gaul/reference-count
Increase FdEntity reference count when returning
2019-03-10 14:27:10 +09:00
1b4d2a32d2 Merge pull request #974 from ggtakec/master
Changed the description order of man page options
2019-03-10 13:43:51 +09:00
b71c90bbe1 Changed the description order of man page options 2019-03-10 04:32:10 +00:00
80344aafd3 Merge pull request #972 from gaul/readme/amazon-linux
Add instructions for Amazon Linux
2019-03-10 13:11:04 +09:00
b5ca400500 Merge pull request #970 from gaul/nocopyapi
Remove from file from stat cache during rename
2019-03-10 12:56:04 +09:00
2e89439120 Merge pull request #969 from gaul/typo/lazy
Fix lazy typo
2019-03-10 12:40:59 +09:00
555410386c Add instructions for Amazon Linux 2019-03-09 22:25:06 +09:00
08b132ddb9 Remove from file from stat cache during rename
This addresses failures with test_rename_before_close when using
nocopyapi.  Note that test_update_time still fails.
2019-03-09 17:53:35 +09:00
1e86cc643d Fix lazy typo 2019-03-09 17:46:02 +09:00
f53503438c Increase FdEntity reference count when returning
Previously s3fs had a race condition where one client could delete
FdEntity that another client was using.  Add a simple concurrent test
which previously failed but now succeeds.  Fixes #964.
2019-03-09 15:55:04 +09:00
0d43d070cc Merge pull request #965 from ggtakec/fix_multi_x
Improvement of curl session pool for multipart
2019-02-27 22:44:25 +09:00
0791fdca2a Merge pull request #960 from kristjanvalur/wtf8
Wtf8
2019-02-27 21:21:38 +09:00
6e8678d5e3 remove lines that wer accidentally duplicated 2019-02-25 16:02:01 +00:00
10d9f75366 Improvement of curl session pool for multipart
Improvement of curl session pool for multipart(2)

Improvement of curl session pool for multipart(3)
2019-02-25 14:46:24 +00:00
77993e607e Merge pull request #961 from gaul/cppcheck
Work around cppcheck warnings
2019-02-24 11:24:28 +09:00
74d8671e54 Work around cppcheck warnings
Follows on to eeb839242b.
2019-02-20 21:55:41 +09:00
4c41eac29c fix documentation and man page 2019-02-20 11:24:29 +00:00
3c97c1b251 merged main 2019-02-19 10:53:00 +00:00
84c671a81a fix indentation 2019-02-19 10:37:43 +00:00
f336bdebcc add command line flag and documentation 2019-02-19 10:32:37 +00:00
e5b8377202 fix comments and code 2019-02-19 10:32:10 +00:00
4f42f4ab0c Enable s3fs encoding and decoding in the fuse interface 2019-02-18 13:36:48 +00:00
11b385820d more robust wtf8 encoding 2019-02-18 12:27:44 +00:00
f1a9eaee54 Merge pull request #958 from gaul/readme/inotify
Document lack of inotify support
2019-02-17 23:28:24 +09:00
ffee8d5f39 Merge pull request #959 from ggtakec/master
Fixed code for latest cppcheck error on OSX
2019-02-17 23:19:17 +09:00
eeb839242b Fixed code for latest cppcheck error on OSX 2019-02-17 13:59:11 +00:00
f7760976a5 Document lack of inotify support
References #45.
2019-02-17 19:45:08 +09:00
ca2d1d873d Adding utility functions to convert invalid utf8 to wtf8 encoding
This is to deal with windows clients who pass in cp1252 as if it
were utf8
2019-02-15 15:57:03 +00:00
951761ee2c Merge pull request #951 from ggtakec/master
Added a non-interactive option to utility mode
2019-02-11 03:03:01 +09:00
231fd001d9 Added a non-interactive option to utility mode
Rebase for resolving conflicts

Deleted interactive mode on utility mode

Fixed minor mistakes
2019-02-10 17:36:18 +00:00
e00afa8128 Merge pull request #957 from gaul/deps/s3proxy-1.6.1
Upgrade to S3Proxy 1.6.1
2019-02-10 23:32:13 +09:00
e9297f39ea Upgrade to S3Proxy 1.6.1
Notably, this improve performance when listing objects using the
filesystem backend, allowing new tests like expanding large tar files.
Release notes:

https://github.com/gaul/s3proxy/releases/tag/s3proxy-1.6.1
2019-02-06 17:06:43 -08:00
314dc5a398 Merge pull request #955 from gaul/clang-tidy/misc
Address miscellaneous clang-tidy warnings
2019-02-06 21:21:54 +09:00
e07cb020cc Merge pull request #954 from gaul/clear-iter
Clear containers instead of individual erases
2019-02-06 21:12:36 +09:00
9f79b9e0da Merge pull request #953 from gaul/readme/s3ql
Update s3ql link
2019-02-06 21:03:28 +09:00
e87e40b3b4 Address miscellaneous clang-tidy warnings
Also add configuration with suppressions.
2019-02-04 22:58:40 -08:00
f0f95478ec Update s3ql link 2019-02-04 21:03:46 -08:00
bd66b57ad3 Merge pull request #952 from gaul/multipart/failed
Automatically abort failed multipart requests
2019-02-04 22:19:27 +09:00
a1d3ff9766 Automatically abort failed multipart requests
This can avoid dangling parts.  However, many transfers fail due to
network errors so we still need other mechanisms to handle these
parts.
2019-02-03 10:29:20 -08:00
7f61a947c2 Merge pull request #950 from ggtakec/master
Added S3FS_MALLOC_TRIM build switch
2019-02-03 17:23:09 +09:00
4d0bef1e90 Clear containers instead of individual erases
This has O(n) runtime instead of O(n log n).
2019-02-02 23:58:43 -08:00
960823fb40 Added S3FS_MALLOC_TRIM build switch 2019-02-03 07:36:17 +00:00
c04e8e7a9d Merge pull request #949 from gaul/503-slow-down
Implement exponential backoff for 503
2019-02-03 15:19:28 +09:00
fb6debd986 Merge pull request #948 from gaul/too-many-parts
Add logging for too many parts
2019-02-03 14:55:54 +09:00
d8185a25aa Merge pull request #946 from gaul/async/completed-tids
Simplify async request completion code
2019-02-03 14:08:49 +09:00
53337a0a28 Merge pull request #944 from gaul/utility-mode
Repair utility mode
2019-02-03 13:59:56 +09:00
ae51556d04 Merge pull request #943 from gaul/hard-link
Return not supported when hard linking
2019-02-03 12:45:21 +09:00
b3de9195a7 Merge pull request #942 from gaul/c++03
Ensure s3fs compiles with C++03
2019-02-03 12:35:49 +09:00
055ecf6ea7 Merge pull request #940 from gaul/parallel-multipart-copy
Copy parts in parallel
2019-02-03 11:44:15 +09:00
c603680e02 Merge pull request #939 from gaul/stringstream-specific
Prefer specific [io]stringstream where possible
2019-02-03 11:06:57 +09:00
814aadd7e3 Merge pull request #938 from gaul/clang-tidy/redundant-void
Remove unneeded void parameter
2019-02-03 10:57:56 +09:00
dce63d1529 Merge pull request #937 from gaul/malloc-trim
Disable malloc_trim
2019-02-03 10:48:15 +09:00
8ff05d8e38 Implement exponential backoff for 503
Amazon returns SlowDown when overloaded.  Also return ENOTSUP for 501
and immediately return EIO for 500 instead of retrying.  Fixes #603.
2019-02-02 00:03:50 -08:00
dfa84b82a8 Add logging for too many parts
References #610.
2019-02-01 19:34:26 -08:00
6ac8618381 Ensure s3fs compiles with C++03 2019-02-01 08:33:59 -08:00
8c527c3616 Simplify async request completion code
Workers now notify the master thread when they complete, unifying the
Linux and macOS code paths.  This also avoids excessive
pthread_tryjoin_np calls.  Follows on to
88cd8feb05.
2019-01-31 22:55:23 -08:00
54a074647e Repair utility mode
This deinitialized S3fsCurl twice and incorrectly calculated V4
signatures.
2019-01-31 18:45:39 -08:00
c5ebf5d328 Copy parts in parallel
S3 can copy multipart much faster than single part due to IO
parallelization.  Renaming a 4 GB file reduces from 72 to 20 seconds
with bigger gains with larger files.
2019-01-31 10:21:39 -08:00
43c6ef560e Return not supported when hard linking
This is more correct than permission denied.
2019-01-30 16:43:04 -08:00
3076abc744 Disable malloc_trim
This avoids walking the entire heap multiple times for complex
operations like readdir.  This does not entirely eliminate the
observed performance regression but does dramatically reduce s3fs CPU
usage.  References #935.  Fixes #936.
2019-01-29 15:29:07 -08:00
07636c8a8d Prefer specific [io]stringstream where possible
These better communicate intent and are slightly more efficient.
2019-01-29 10:44:33 -08:00
35d55ee513 Remove unneeded void parameter
This is implicit in C++.  Found and fixed via clang-tidy.
2019-01-28 23:22:27 -08:00
a442e843be Merge pull request #934 from ggtakec/master
Checked and corrected all typo
2019-01-27 21:33:16 +09:00
c0cf90cf8b Checked and corrected all typo 2019-01-27 12:04:29 +00:00
3b1cc3b197 Merge pull request #933 from gaul/cache/remove-mirror-path
Remove mirror path when deleting cache
2019-01-27 16:15:49 +09:00
a0c1f30ae7 Merge pull request #932 from gaul/autolock
Prefer AutoLock for synchronization
2019-01-27 15:59:18 +09:00
8822a86709 Merge pull request #931 from gaul/doc/typo
Correct sigv2 typo
2019-01-27 15:48:24 +09:00
98f397de0e Merge pull request #930 from gaul/doc/md5-multipart
Correct enable_content_md5 docs
2019-01-27 15:36:56 +09:00
fd4d23f8f7 Merge pull request #926 from kzidane/master
Accept paths with : in them
2019-01-27 15:23:24 +09:00
4820f0a42b Merge pull request #925 from gaul/clang-tidy/delete-null
Remove redundant null checks before delete
2019-01-27 15:15:31 +09:00
807a618cf7 Merge pull request #924 from gaul/clang-tidy/empty
Prefer empty over size checks
2019-01-27 15:04:52 +09:00
a93e500b44 Remove mirror path when deleting cache
Fixes #827.
2019-01-25 18:10:03 -08:00
92d3114584 Prefer AutoLock for synchronization
This simplifies the code and fixes an issue with unlocked access.
Also use a recursive lock for StatCache to avoid races between
lock..unlock..lock sequences.
2019-01-25 15:28:41 -08:00
5062d6fbd9 Correct sigv2 typo 2019-01-25 14:30:30 -08:00
7d14ebaf09 Correct enable_content_md5 docs
Both S3fsCurl::PutRequest and S3fsCurl::UploadMultipartPostSetup can
calculate and send Content-MD5 to the server.  Remove spurious comment
about large files and make man page and help consistent.
References #929.
2019-01-25 14:27:52 -08:00
cd794a6985 Accept paths with : in them 2019-01-23 14:56:25 -05:00
84b421d6ef Prefer empty over size checks
Found and fixed via clang-tidy.
2019-01-23 11:30:28 -08:00
8316da5bbe Remove redundant null checks before delete
Found by clang-tidy.
2019-01-23 11:25:25 -08:00
fa287aeef7 Merge pull request #923 from ggtakec/master
Reverted automatic region change and changed messages
2019-01-23 23:00:31 +09:00
caaf4cac55 Reverted #912(Automatic region change) and added message 2019-01-23 13:23:03 +00:00
010276ceab Merge pull request #921 from gaul/clang-tidy/redundant-string-init
Remove redundant string initializations
2019-01-23 19:44:59 +09:00
f219817eb3 Merge pull request #920 from gaul/clang-tidy/string-copy
Remove unnecessary string copies
2019-01-23 19:30:55 +09:00
d487348d21 Merge pull request #919 from gaul/test/mv-nonempty-dir
Add test for mv non-empty directory
2019-01-23 19:21:12 +09:00
eb0b29708f Merge pull request #918 from gaul/overwrite-file-range
Load tail range during overwrite
2019-01-23 19:12:23 +09:00
877842a720 Merge pull request #917 from gaul/readme/aws-cli
Reference better-known AWS CLI for compatibility
2019-01-23 18:38:08 +09:00
1fc25e8c3f Remove redundant string initializations
Found and fixed via clang-tidy.
2019-01-22 23:16:37 -08:00
61ecafd426 Remove unnecessary string copies
Found via clang-tidy.
2019-01-22 23:09:37 -08:00
79bd3441eb Add test for mv non-empty directory 2019-01-22 22:13:17 -08:00
5f5da4b2cb Load tail range during overwrite
Previously s3fs experienced data loss when writing to the middle of a
file.  Corrupt files would have the expected data from 0..offset+size
but unexpected NUL bytes from offset+size..EOF.  References #808.
2019-01-22 22:02:40 -08:00
dede19d8c0 Reference better-known AWS CLI for compatibility 2019-01-21 17:32:57 -08:00
fada95f58e Merge pull request #914 from gaul/readdir/head-of-line
Issue readdir HEAD requests without batching
2019-01-21 22:10:50 +09:00
014b8c5982 Merge pull request #913 from gaul/assert
Prefer abort over assert(false)
2019-01-21 21:56:41 +09:00
46d79c5bc2 Issue readdir HEAD requests without batching
Previously s3fs would issue a batch of HEAD requests and wait for all
to succeed before issuing the next batch.  Now it issues the first
batch and only waits for a single call to succeed before issuing the
next call.  This can improve performance when one call lags due to
network errors.  I measured 25% improvement with the same level of
parallelism.  This commit also reparents parallelism knobs for
consistency.  Follows on to 88cd8feb05.
Fixes #223.
2019-01-20 18:07:22 -08:00
40ba3b44a1 Prefer abort over assert(false)
The compiler can remove the latter when compiled with NDEBUG which may
cause unintended control flow.
2019-01-20 12:30:27 -08:00
beadf95975 Merge pull request #912 from ggtakec/master
Automatic region change made possible other than us-east-1(default)
2019-01-20 20:13:07 +09:00
2887f8916b Automatic region change made possible other than us-east-1(default) 2019-01-20 10:51:49 +00:00
0c9a8932f7 Merge pull request #911 from ggtakec/master
Added detail error message when HTTP 301/307 status
2019-01-20 19:31:04 +09:00
ac72431195 Added detail error message when HTTP 301/307 status 2019-01-20 10:07:58 +00:00
2a7877beff Merge pull request #910 from ggtakec/master
Added a missing extension to .gitignore, and formatted dot files
2019-01-20 18:38:37 +09:00
7a56459103 Added a missing extension to .gitignore, and formatted dot files 2019-01-20 09:18:40 +00:00
5292fa74d1 Merge pull request #909 from ggtakec/master
Ignore after period character of floating point in x-amz-meta-mtime
2019-01-20 17:58:55 +09:00
f2184e34dd Ignore after period character of floating point in x-amz-meta-mtime 2019-01-20 08:28:06 +00:00
1d4867830b Merge pull request #908 from ggtakec/master
Added an error message when HTTP 301 status
2019-01-20 16:59:43 +09:00
36a4903843 Added an error message when HTTP 301 status 2019-01-20 07:17:40 +00:00
c83a3e67c9 Merge pull request #885 from LutzFinsterle2019/master
Update s3fs_util.cpp for correspondence of Nextcloud contype
2019-01-20 15:32:58 +09:00
05014c49c8 Merge pull request #906 from gaul/doc/https
Prefer HTTPS links where possible
2019-01-20 15:10:51 +09:00
aa69107165 Merge pull request #905 from gaul/clang-tidy/redundant
Fix comparison in s3fs_strtoofft
2019-01-20 15:01:40 +09:00
d373b0eca3 Merge pull request #904 from gaul/clang-tidy/c-str
Remove unnecessary calls to std::string::c_str
2019-01-20 14:13:46 +09:00
6aa40b2747 Merge pull request #903 from gaul/clang-tidy/find_char
Prefer find(char) over find(const char *)
2019-01-20 14:05:06 +09:00
34c3bfe408 Merge pull request #902 from gaul/clang-tidy/pass-by-value
Avoid pass-by-value when not necessary
2019-01-20 13:45:44 +09:00
6ac56e722d Merge pull request #901 from gaul/clang-tidy/leaks
Plug memory leaks
2019-01-20 12:41:08 +09:00
61dc7f0a70 Merge pull request #900 from gaul/leak
Plug memory leak
2019-01-20 12:30:31 +09:00
9f000957dd Merge pull request #899 from gaul/response-code
Tighten up HTTP response code check
2019-01-20 11:16:23 +09:00
b2141313e2 Merge pull request #898 from gaul/rename-before-close
Flush file before renaming
2019-01-20 10:13:20 +09:00
aa9bd1fa3c Prefer HTTPS links where possible
Fix a few stale links as well.
2019-01-18 11:09:08 -08:00
5a2dc03a1c Fix comparison in s3fs_strtoofft
Also backfill unit tests.  Document limitations.  Found via
clang-tidy.
2019-01-17 22:59:25 -08:00
508fafbe62 Remove unnecessary calls to std::string::c_str
Found via clang-tidy.
2019-01-17 22:05:16 -08:00
e29548178b Prefer find(char) over find(const char *)
The former can be faster.  Found via clang-tidy.
2019-01-17 20:24:24 -08:00
ab2f36f202 Plug memory leaks
Found via clang-tidy.
2019-01-17 18:54:34 -08:00
b8c9fcfd70 Avoid pass-by-value when not necessary
This requires unnecessary memcpy.  Found via clang-tidy.
2019-01-17 18:22:11 -08:00
58ce544e83 Plug memory leak
Previously this appended to an empty list, zeroed the list, then
appended to the list.  Instead zero the list first and then append.
This also enables sending Content-MD5 which can eagerly detect
transmission errors.  Found via Valgrind.
2019-01-17 16:24:34 -08:00
e98ce36301 Tighten up HTTP response code check
Previously s3fs considered 3xx codes as successful.  When writing an
object to a misconfigured region, s3fs did not propagate the 301 as a
write error to the client.  References #693.
2019-01-17 15:04:59 -08:00
6401b4ae92 Flush file before renaming
Previously s3fs could copy the zero-byte stub object without including
any pending writes.  Fixes #145.
2019-01-17 12:05:10 -08:00
25b49e1a2e Merge pull request #894 from gaul/default-mode
Default uid/gid/mode when object lacks permissions
2019-01-16 18:48:54 +09:00
c7def35b54 Merge pull request #895 from gaul/bucket-name-dot
Emit more friendly error for buckets with dots
2019-01-16 18:39:47 +09:00
ddba1c63c5 Merge pull request #893 from gaul/ctime
Store and retrieve file change time
2019-01-16 18:30:15 +09:00
c512516e14 Emit more friendly error for buckets with dots
These fail SSL certificate checks due to the *.s3.amazon.com wildcard.
Fixes #284.
2019-01-14 18:47:36 -08:00
2c43b1e12b Store and retrieve file change time
This introduces a new header with the change time; existing objects
will report modification time.  Fixes #771.
2019-01-14 10:05:11 -08:00
b68d97c6bf Merge pull request #892 from gaul/test/xattr
Repair xattr tests
2019-01-14 21:26:46 +09:00
f1757e4343 Merge pull request #888 from gaul/readme
Add Server Fault to FAQs
2019-01-14 21:17:06 +09:00
e2d5641d99 Default uid/gid/mode when object lacks permissions
This addresses a common use case when interacting with objects from
both s3fs and other S3 tools.  Fixes #890.
2019-01-13 21:57:23 -08:00
523fe1e309 Repair xattr tests
These did not run due to missing use_xattr flag and Travis
misconfiguration.
2019-01-13 18:54:16 -08:00
c985b5e4d0 Corrected Comment to C++ style 2019-01-12 10:19:48 +01:00
786f1a8fc7 Add Server Fault to FAQs
Also correctly format Stack Overflow.
2019-01-10 11:17:32 -08:00
18cb2e2662 Update s3fs_util.cpp
Sorry for answering late, have been busy lately.
The comment is: "Nextcloud stores Directory objects with this mime type when mounting a Bucket as external Storage"
2019-01-10 07:44:36 +01:00
743c706b0a Update s3fs_util.cpp
Nextcloud Compatibility in directory mime-types
2019-01-07 07:41:27 +01:00
4ed0e5f35a Merge pull request #882 from earlchew/issue-817
[curl] Assume long encryption keys are base64 encoded
2019-01-06 17:29:04 +09:00
fd6b37d3da Merge pull request #877 from gaul/aws/credentials
Check arguments and environment before .aws/creds
2019-01-06 17:03:11 +09:00
56e24de0d4 Merge pull request #870 from gaul/typos
Correct typos in command-line parsing
2019-01-06 16:21:46 +09:00
2780043a7d Merge pull request #856 from gaul/doc/icon
Add icon for s3fs
2019-01-06 15:54:24 +09:00
54c9e48bb7 Merge pull request #874 from gaul/cppcheck-1.86
Address cppcheck 1.86 errors
2019-01-06 15:20:28 +09:00
ed5795eead [curl] Assume long encryption keys are base64 encoded
Correct tabs and whitespace.

Signed-off-by: Earl Chew <earl_chew@yahoo.com>
2019-01-05 21:08:41 +00:00
3d225163f8 Correct typos in command-line parsing
Also fix stray macOS references.  References #869.
2019-01-02 14:40:57 -08:00
0569cec3ea Check arguments and environment before .aws/creds
Fixes #857.  Fixes #864.
2018-12-20 15:51:32 -08:00
a2f8ac535e Address cppcheck 1.86 errors
Lifetime, shadowing, and unused variables.  Found via the Travis macOS
builder.
2018-12-20 14:56:31 -08:00
29355d75b0 Add icon for s3fs
This is suitable for the s3fs-fuse organization.
2018-12-15 17:12:28 -08:00
d9e89deef6 Merge pull request #865 from orozery/multihead_warning_check
fix multihead warning check
2018-11-29 20:53:47 +09:00
6b051eac47 Merge pull request #866 from Basavaraju013/master
Multi-arch support for ppc64le
2018-11-29 20:37:02 +09:00
da997de918 Merge pull request #861 from mcgitty/patch-1
Add 'profile' option to command line help.
2018-11-29 20:15:01 +09:00
d97094fb8d Multi-support for ppc64le 2018-11-28 05:15:09 -06:00
b91fc5409e fix multihead warning check 2018-11-28 09:54:02 +02:00
3c970646d1 Add 'profile' option to command line help. 2018-11-19 08:26:23 -08:00
a92668ae78 Merge pull request #859 from gaul/upload-remove-batching
Upload S3 parts without batching
2018-11-18 22:27:20 +09:00
88cd8feb05 Upload S3 parts without batching
Previously s3fs would issue a batch of uploads and wait for all to
succeed before issuing the next batch.  Now it issues the first batch
and only waits for a single part to succeed before uploading the next
part.  This can improve performance when one part lags due to network
errors.  Fixes #183.
2018-11-16 18:32:38 -08:00
91c16f826a Merge pull request #855 from gaul/readme/stackoverflow
Include StackOverflow in FAQs
2018-11-14 22:32:10 +09:00
d4d60ff315 Include StackOverflow in FAQs 2018-11-13 22:19:17 -08:00
e8033f96de Merge pull request #853 from gaul/readme-tilde
Replace ~ with ${HOME} in examples
2018-11-11 11:47:44 +09:00
5fba542a29 Merge pull request #852 from gaul/aws-credentials-file
Allow credentials from ${HOME}/.aws/credentials
2018-11-11 11:37:38 +09:00
44de3ffa05 Merge pull request #851 from gaul/list-object-max-keys
Correctly compare list_object_max_keys
2018-11-11 11:26:31 +09:00
2efa6df028 Merge pull request #849 from gaul/readme
Correct typo
2018-11-11 11:17:05 +09:00
9e530c86ae Allow credentials from ${HOME}/.aws/credentials
This matches the configuration from popular tools like AWS CLI and
allows multiple profile names via -o profile=name.  The existing
credential mechanisms continue to work.  Fixes #822.
2018-11-04 17:47:07 -08:00
95857733a1 Replace ~ with ${HOME} in examples
Several of these do not work since the shell does not replace ~ in the
middle of a token, e.g., -o passwd=~/.passwd .  Replace all of them
for consistency.  Fixes #836.
2018-11-04 17:45:16 -08:00
664f910083 Correctly compare list_object_max_keys
Previously this did not allow an argument.  Fixes #843.
References #793.
2018-11-04 10:49:35 -08:00
735e4b0848 Correct typo 2018-10-29 21:42:48 -07:00
e8d76a6f58 Merge pull request #840 from juliogonzalez/macOS
Replace all mentions to MacOS X to macOS
2018-10-28 20:33:51 +09:00
0a6926be54 Merge pull request #835 from juliogonzalez/generic-compilation
Make the compilation instructions generic
2018-10-28 20:00:21 +09:00
830a971bde Replace all mentions to MacOS X to macOS 2018-10-14 23:23:19 +02:00
4779d14d7d Make the compilation instructions generic 2018-10-08 22:27:01 +02:00
8929a27a24 Merge pull request #834 from juliogonzalez/issue-improvements
Improve template for issues
2018-10-09 00:37:20 +09:00
eea624c171 Merge pull request #833 from juliogonzalez/doc
New installation instructions for Fedora >= 27 and CentOS7
2018-10-09 00:05:36 +09:00
cdaf4a9674 Merge branch 'master' into doc 2018-10-08 23:56:20 +09:00
6fe92d5ed6 Merge pull request #832 from gaul/hex
Simplify hex conversion
2018-10-08 23:03:42 +09:00
8649a68766 Merge pull request #831 from JoohnSF/onezone_ia_support
Add support for storage class ONEZONE_IA.
2018-10-08 22:57:12 +09:00
af005b6e5e Merge pull request #826 from juliogonzalez/centos-setup
For RPM distributions fuse-libs is enough
2018-10-08 22:50:29 +09:00
b19d2ae78f Improve template for issues 2018-10-07 01:20:10 +02:00
5634f9bdcd New installation instructions for Fedora >= 27 and CentOS7 2018-10-07 00:52:45 +02:00
c703fa15c0 Simplify hex conversion
Addresses GCC 8 warning:

common_auth.cpp: In function ‘std::__cxx11::string s3fs_sha256sum(int, off_t, ssize_t)’:
common_auth.cpp:84:12: warning: ‘char* strncat(char*, const char*, size_t)’ output may be truncated copying 2 bytes from a string of length 2 [-Wstringop-truncation]
    strncat(sha256, hexbuf, 2);
2018-10-01 19:08:27 -07:00
d9c106cfde Add support for storage class ONEZONE_IA. 2018-09-30 14:27:31 +02:00
203f78fdae For RPM distributions fuse-libs is enough 2018-09-23 19:35:17 +02:00
c5af62b023 Merge pull request #820 from gaul/big-writes
Enable big writes if capable
2018-09-17 17:24:06 +09:00
dcd70daf48 Merge pull request #819 from soulprovidr/master
#691: Made instructions for creating password file more obvious.
2018-09-17 17:01:53 +09:00
8263919b0e Merge pull request #812 from mapreri/typo
Fix typo s/mutliple/multiple/
2018-09-17 16:52:48 +09:00
97488e603f Merge pull request #804 from DreamFlasher/patch-2
add Backblaze B2
2018-09-17 16:43:55 +09:00
41c23adb0e [curl] Assume long encryption keys are base64 encoded
Amazon SSE-C https://tinyurl.com/ychug4cg writes:

> Use this header to provide the 256-bit, base64-encoded encryption key
> for Amazon S3 to use to encrypt or decrypt your data.

It seems likely that future keys would be as long, or longer, so
this change assumes that text longer than 32 characters are keys
that are base64 encoded.

Signed-off-by: Earl Chew <earl_chew@yahoo.com>
2018-09-16 21:23:22 +00:00
a85183d42c Enable big writes if capable
Fixes #813.
2018-09-10 22:21:51 -07:00
45b67b9604 #691: Made instructions for creating password file more obvious. 2018-09-09 23:11:12 -05:00
c376efdd28 Fix typo s/mutliple/multiple/
Signed-off-by: Mattia Rizzolo <mattia@mapreri.org>
2018-08-19 00:14:57 +02:00
4c5f510207 add Backblaze B2
this is relevant because Backblaze B2 is fairly popular and thus mentioning it helps s3fs
2018-07-17 13:49:31 +02:00
06032aa661 Merge pull request #795 from ggtakec/master
Updated ChangeLog and configure.ac for release 1.84
2018-07-08 18:22:54 +09:00
e8fb2aefb3 Updated ChangeLog and configure.ac for release 1.84 2018-07-08 09:06:52 +00:00
3cb6c5e161 Merge pull request #793 from ggtakec/master
Added list_object_max_keys option based on #783 PR
2018-07-08 13:08:47 +09:00
7e0c53dfe9 Added list_object_max_keys option based on #783 PR 2018-07-08 03:49:10 +00:00
c2ca7e43b6 Merge pull request #789 from juliogonzalez/doc-opensuse-suse
Instructions for SUSE and openSUSE prebuilt packages
2018-07-08 11:42:05 +09:00
ae47d5d349 Merge pull request #786 from ambiknai/log_enhancements
Log messages for 5xx and 4xx HTTP response code
2018-07-08 11:28:54 +09:00
35d3fce7a0 Review comment: Include the error code being returned 2018-07-06 05:14:32 -04:00
4177d8bd3b Review comment: Include the error code being returned 2018-07-06 03:03:57 -04:00
ad5349a488 Changes as per review comments 2018-07-05 05:02:04 -04:00
6b57a8c1fc Instructions for SUSE and openSUSE prebuilt packages 2018-07-05 10:23:26 +02:00
92a4034c5e Log messages for 5xx and 4xx HTTP response code 2018-07-04 03:50:45 -04:00
3e4002df0d Merge pull request #780 from wjt/initialize-libgcry
gnutls_auth: initialize libgcrypt
2018-06-24 12:48:08 +09:00
1b9ec7f4fc Merge pull request #774 from nkkashyap/master
Option for IAM authentication endpoint
2018-06-24 12:36:23 +09:00
4a7c4a9e9d Merge pull request #781 from ggtakec/master
Fixed an error by cppcheck on OSX
2018-06-24 12:22:35 +09:00
0d3fb0658a Fixed a error by cppcheck on OSX 2018-06-24 02:38:59 +00:00
73cf2ba95d gnutls_auth: initialize libgcrypt
Without this change, the following warning appears in the syslog/journal
during startup:

  Libgcrypt warning: missing initialization - please fix the application

From the [documentation][0]:

> The function `gcry_check_version` initializes some subsystems used by
> Libgcrypt and must be invoked before any other function in the
> library.

Fixes #524, which says:

> gnutls is initialized by gnutls_global_init() function and
> gcry_check_version() function for initializing libgcry is called from
> this gnutls_global_init().

I checked the gnutls source and it hasn't contained a call to
gcry_check_version() since the libgcrypt backend was removed in 2011
(commit 8116cdc8f131edd586dad3128ae35dd744cfc32f). In any case, the
gcry_check_version() documentation continues:

> It is important that these initialization steps are not done by a
> library but by the actual application.

so it would be incorrect for a library used by s3fs to initialize
libgcrypt.

[0]: https://www.gnupg.org/documentation/manuals/gcrypt/Initializing-the-library.html
2018-06-21 20:55:00 +01:00
5a481e6a01 Option for IBM IAM auth endpoint added return 2018-06-04 16:44:14 +05:30
d8e12839af Option for IBM IAM auth endpoint 2018-05-31 16:02:48 +05:30
3bf05dabea Merge pull request #769 from orozery/revert_to_async_read
Revert "enable FUSE read_sync by default"
2018-05-28 20:23:54 +09:00
d4e86a17d1 Revert "enable FUSE read_sync by default"
This reverts commit 86b0921ac4.

Conflicts:
	src/s3fs.cpp
2018-05-28 13:49:54 +03:00
6555e7ebb0 Merge pull request #768 from ggtakec/master
Fixed memory leak
2018-05-27 20:10:16 +09:00
ae9d8eb734 Fixed memory leak 2018-05-27 10:48:03 +00:00
e49d594db4 Merge pull request #766 from gaul/s3fs-python
Remove s3fs-python
2018-05-27 16:43:27 +09:00
66bb0898db Merge pull request #765 from gaul/debian
Add Debian installation instructions
2018-05-27 16:35:51 +09:00
b323312312 Remove s3fs-python
This no longer exists.
2018-05-23 16:06:41 -07:00
58e52bad4f Add Debian installation instructions 2018-05-23 16:03:02 -07:00
57b2a60172 Merge pull request #764 from orozery/remove_false_multihead_warnings
Remove false multihead warnings
2018-05-23 22:38:35 +09:00
212bbbbdf0 Merge pull request #763 from orozery/cleanup_share_after_handles
cleanup curl handles before curl share
2018-05-23 22:30:36 +09:00
a0e62b5588 Merge pull request #762 from gaul/s3proxy-1.6.0
Upgrade to S3Proxy 1.6.0
2018-05-23 22:23:33 +09:00
e9831dd772 Merge pull request #761 from gaul/ubuntu-16.04
Simplify installation for Ubuntu 16.04
2018-05-23 22:15:01 +09:00
da95afba8a Merge pull request #756 from orozery/optimize_defaults
Optimize defaults
2018-05-23 22:05:00 +09:00
0bd875eb9e remove false readdir_multi_head warnings 2018-05-22 17:10:50 +03:00
af63a42773 cleanup curl handles before curl share 2018-05-21 13:20:09 +03:00
ad9a374229 Simplify installation for Ubuntu 16.04
Also reorganize installation vs. compilation.
2018-05-16 17:40:13 -07:00
1b86e4d414 Upgrade to S3Proxy 1.6.0
Release notes:

https://github.com/gaul/s3proxy/releases/tag/s3proxy-1.6.0
https://github.com/gaul/s3proxy/releases/tag/s3proxy-1.5.5
https://github.com/gaul/s3proxy/releases/tag/s3proxy-1.5.4
2018-05-16 16:38:17 -07:00
86b0921ac4 enable FUSE read_sync by default 2018-05-06 16:10:36 +03:00
dbe98dcbd2 Merge pull request #755 from ggtakec/master
Added reset curl handle when returning to handle pool
2018-05-06 21:35:39 +09:00
4a72b60707 increase default stat cache size from 1000 to 100000 2018-05-06 15:31:07 +03:00
7a4696fc17 recommend openssl over gnutls for performance 2018-05-06 15:29:42 +03:00
e3de6ea458 Added reset curl handle when returning to handle pool 2018-05-06 12:11:53 +00:00
1db4739ed8 Merge pull request #754 from nkkashyap/master
Validate the URL format for http/https
2018-05-06 21:02:33 +09:00
25375a6b48 Validate the URL fixed inefficient usage of find 2018-05-04 11:24:32 +05:30
ca87df7d44 Validate the URL format for http/https 2018-05-03 22:08:28 +05:30
d052dc0b9d Merge pull request #753 from cfz/master
fix xpath selector in bucket listing
2018-05-02 12:04:12 +09:00
3f542e9cf5 Merge pull request #745 from orozery/handle_mkdir_exists
don't fail mkdir when directory exists
2018-05-02 11:37:18 +09:00
04493de767 fix xpath selector in bucket listing
the original implementation in get_base_exp() depends on the order of xml return from the server.
patriotically, when listing a directory with sub directory(s), the xml document response contains more than 2 <Prefix> nodes(some of them are in <CommonPrefixes> node).
the source code arbitrarily select the first one in the documents (nodes->nodeTab[0]->xmlChildrenNode).
some s3 compatible service return the list-bucket result in different result, leading the s3fs to a wrong behavior
2018-04-23 15:11:29 +08:00
4fdab46617 don't fail mkdir when directory exists 2018-04-08 11:13:47 +03:00
1a23b880d5 Merge pull request #739 from orozery/cleanup_failing_curl_handles
cleanup curl handle state on retries
2018-04-01 22:45:04 +09:00
b3c376afbe Merge pull request #733 from phxvyper/enhance/dupe-bucket-error
More useful error message for dupe entries in passwd file
2018-04-01 22:11:00 +09:00
adcf5754ae cleanup failing curl handles on retries 2018-03-29 13:56:08 +03:00
0863672e27 add a more helpful error message for when there are multiple entries for the same bucket in the passwd file 2018-03-13 14:37:34 -07:00
0f503ced25 Merge pull request #729 from dmgk/master
FreeBSD build fixes
2018-03-04 16:36:31 +09:00
987a166bf4 Merge pull request #726 from orozery/instance_name_logging
add an instance_name option for logging
2018-03-04 15:41:12 +09:00
57b6f0eeaf Merge pull request #724 from orozery/dont_fail_multirequest
don't fail multirequest on single thread error
2018-03-04 15:35:29 +09:00
f71a28f9b9 Merge pull request #714 from orozery/reduce_lock_contention
reduce lock contention on file open
2018-03-04 13:36:08 +09:00
45c7ea9194 Merge pull request #710 from orozery/disk_space_reservation
add disk space reservation
2018-03-04 13:27:25 +09:00
c9f4312588 FreeBSD build fixes 2018-03-02 15:58:52 -05:00
8b657eee41 add disk space reservation 2018-02-28 19:20:23 +02:00
b9c9de7f97 Merge pull request #712 from chrilith/master
Added Cygwin build options
2018-02-28 23:07:54 +09:00
e559f05326 Merge pull request #704 from vadimeremeev/patch-1
Update README.md with details about .passwd-s3fs
2018-02-28 22:22:01 +09:00
824124fedc Merge pull request #727 from ggtakec/master
Fixed Travis CI error about cppcheck - #713
2018-02-28 22:04:04 +09:00
be9d407fa0 Fixed cppcheck error on osx 2018-02-28 12:29:58 +00:00
c494e54320 Fixed cppcheck error on osx 2018-02-28 12:06:06 +00:00
b52b6f3fc5 add an instance_name option for logging 2018-02-28 09:51:35 +02:00
82c9733101 don't fail multirequest on single thread error 2018-02-26 12:06:08 +02:00
a45ff6cdaa Fixed cppcheck error and clean ^M code 2018-02-25 13:08:41 +00:00
960d45c853 Fixed cppcheck error on osx 2018-02-25 08:51:19 +00:00
246b767b64 Remove space in front of ~/.passwd-s3fs 2018-02-05 16:49:02 +07:00
0edf056e95 reduce lock contention on file open 2018-02-04 17:13:58 +02:00
88819af2d8 Added Cygwin build options 2018-02-02 15:58:10 +01:00
b048c981ad Update README.md with details about .passwd-s3fs 2017-12-22 16:20:02 +07:00
e1dafe76dd Merge pull request #701 from ggtakec/master
Updated ChangeLog and configure.ac for release 1.83
2017-12-17 16:53:49 +09:00
1a2e63ecff Updated ChangeLog and configure.ac for release 1.83 2017-12-17 07:37:19 +00:00
a60b32cb80 Merge pull request #699 from casidiablo/patch-1
Fix dbglevel usage
2017-12-17 15:55:24 +09:00
6b58220009 Merge pull request #697 from pwulff/master
Fixing race condition in FdEntity::GetStats
2017-12-17 15:46:48 +09:00
a841057679 Merge pull request #695 from orozery/fix_parallel_download_condition
fix condition for parallel download
2017-12-17 15:41:43 +09:00
ee6abea956 Race condition in FdManager::Rename because no mutex is used. 2017-12-15 15:27:51 +01:00
8b0acd75e0 Fix dbglevel usage 2017-12-14 14:37:18 -08:00
cea7d44717 Fixing race condition in FdEntity::GetStats 2017-12-13 10:49:00 +01:00
0da87e75fe fix condition for parallel download 2017-12-04 16:07:33 +02:00
566961c7a5 Merge pull request #692 from ggtakec/master
Updated template md files for issue and pr
2017-11-26 15:40:27 +09:00
ac65258d30 Updated template md files for issue and pr 2017-11-26 06:20:41 +00:00
35261e6dba Merge pull request #690 from ggtakec/master
Added option ecs description to man page
2017-11-23 21:40:11 +09:00
2818f23ba5 Added option ecs description to man page 2017-11-23 12:21:56 +00:00
88f071ea22 Merge pull request #669 from orozery/ibm_auth
add IBM IAM authentication support
2017-11-23 21:15:08 +09:00
bd4bc0e7f1 add support for IBM IAM authentication 2017-11-23 12:01:52 +02:00
890c1d53ff Merge pull request #688 from ggtakec/master
Improved use of temporary files - #678
2017-11-23 18:46:31 +09:00
026260e7a1 Improved use of temporary files 2017-11-23 09:18:11 +00:00
99fe93b7f1 Merge pull request #684 from gaul/signedness
Correct signedness warning
2017-11-23 17:33:46 +09:00
b764c53020 Merge pull request #686 from orozery/remove_jsoncpp
remove use of jsoncpp
2017-11-23 17:08:40 +09:00
11bd7128d2 remove use of jsoncpp 2017-11-22 13:36:27 +02:00
7cda32664b Correct signedness warning
Fixes regression from 0418e53b3c.
2017-11-19 11:14:37 -08:00
4c73a0ae56 Merge pull request #681 from ggtakec/master
Changed functions about reading passwd file
2017-11-19 21:06:45 +09:00
97fc845a6a Changed functions about reading passwd file. 2017-11-19 11:49:11 +00:00
7d9ac0163b Changed functions about reading passwd file. 2017-11-19 11:38:12 +00:00
d903e064e0 Merge pull request #677 from gaul/gitignore
Add s3proxy to .gitignore
2017-11-19 16:44:24 +09:00
e1928288fe Merge pull request #676 from gaul/sstream
Move str definition from header to implementation
2017-11-19 16:34:15 +09:00
6ab6412dd3 Merge pull request #679 from ggtakec/master
README.md Addition
2017-11-19 16:24:51 +09:00
30b7a69d3d README.md Addition 2017-11-19 07:03:39 +00:00
ccd0a446d8 Merge pull request #675 from gaul/define
Reduce use of preprocessor
2017-11-19 16:02:24 +09:00
0418e53b3c Reduce use of preprocessor
This provides type-safety and avoids token expansion side effects.
2017-11-18 22:40:06 -08:00
bad48ab59a Merge pull request #671 from psyvision/master
Add support for ECS metadata endpoint
2017-11-19 14:43:06 +09:00
bbad76bb71 Move str definition from header to implementation
Also clean up some char * to std::string conversions.
2017-11-18 11:34:34 -08:00
6c1bd98c14 Add s3proxy to .gitignore 2017-11-18 11:10:56 -08:00
b95e4acaeb Remove debug logging statements 2017-11-08 15:52:35 +00:00
c238701d09 Corrected ECS headers 2017-11-08 15:21:49 +00:00
60d2ac3c7a Adding x-amz-security-token header 2017-11-08 15:09:59 +00:00
967ef4d56b Corrected fat finger mistakes 2017-11-08 13:14:49 +00:00
ad57bdda6c Corrected keycount check 2017-11-08 13:06:22 +00:00
a0b69d1d3d Corrected keyval[].c_str() 2017-11-08 13:01:52 +00:00
5df94d7e33 Add debug messages 2017-11-08 09:50:39 +00:00
1cbe9fb7a3 Gotta pass that cppcheckgit add . 2017-11-07 21:41:51 +00:00
395f736753 Lower jsoncpp requirement 2017-11-07 21:38:01 +00:00
065516c5f3 Add jsoncpp to tavis config 2017-11-07 21:29:07 +00:00
8660abaea2 Use jsoncpp to parse AWS JSON 2017-11-07 21:20:02 +00:00
366f0705a0 ECS credentials bug fixes 2017-11-06 21:45:58 +00:00
ccea87ca68 Added check for is_ecs during get_access_keys
We need to presume that if `is_ecs` we are deferring access key loading
2017-11-06 11:02:27 +00:00
5d54883e2f Remove commented out code 2017-11-05 19:25:34 +00:00
662f65c3c8 Add support for ECS metadata endpoint 2017-11-05 19:24:02 +00:00
259f028490 Merge pull request #670 from ggtakec/master
Fixed a bug in S3fsCurl::LocateBundle
2017-11-05 20:37:12 +09:00
5db550a298 Fixed a bug in S3fsCurl::LocateBundle 2017-11-05 11:26:05 +00:00
e3c77d2906 Merge pull request #664 from orozery/auth_refactor
auth headers insertion refactoring
2017-11-05 15:14:40 +09:00
ba00e79253 Merge pull request #668 from ggtakec/master
Changed .travis.yml for fixing not found gpg2 on osx
2017-11-05 14:47:41 +09:00
c1791f920e Changed .travis.yml for fixing not found gpg2 on osx 2017-11-05 05:32:41 +00:00
df3803c7b7 Merge pull request #663 from gaul/orgmeta-lock
Lock FdEntity when mutating orgmeta
2017-11-05 13:53:14 +09:00
384b4cbafa auth headers insertion refactoring 2017-10-30 11:52:58 +02:00
40501a7a73 Lock FdEntity when mutating orgmeta
References #654.
2017-10-23 22:41:42 -07:00
ab89b4cd4a Merge pull request #659 from ggtakec/master
Do not fail updating directory when removing old-style object(ref #658)
2017-10-15 21:56:35 +09:00
48e0d55c8e Merge pull request #660 from s3fs-fuse/patch
Refixed s3fs_init message(ref #652)
2017-10-15 16:01:45 +09:00
1eba27a50a Refixed s3fs_init message(ref #652) 2017-10-15 06:45:19 +00:00
41206fa0e2 Do not fail updating directory when removing old-style object(ref #658) 2017-10-15 05:03:44 +00:00
21cf1d64e5 Merge pull request #652 from jurafxp/fix-error
Fix s3fs_init message
2017-10-15 12:36:12 +09:00
ae91b6f673 Fix s3fs_init message 2017-10-01 00:08:00 +02:00
f4515b5cfa Merge pull request #646 from andrewgaul/s3proxy-pid
Simplify S3Proxy PID handling
2017-09-20 05:17:00 +09:00
6c57cde7f9 Merge pull request #645 from andrewgaul/s3proxy-ssl
Configure S3Proxy for SSL
2017-09-19 21:39:32 +09:00
5014c1827b Simplify S3Proxy PID handling
Also remove log prefixing since newer S3Proxy versions do this
already.  Finally remove unnecessary wait.
2017-09-17 20:19:56 -07:00
f531e6aff2 Configure S3Proxy for SSL
This also demonstrates that SSL certificate checking occurs and the
tests must disable it for S3Proxy's self-signed certificate.
References #640.
2017-09-17 16:16:18 -07:00
c5c110137b Merge pull request #644 from ggtakec/master
Fixed with unnecessary equal in POST uploads url argment - #643
2017-09-17 20:08:53 +09:00
5957d9ead0 Fixed with unnecessary equal in POST uploads url argment - #643 2017-09-17 10:52:28 +00:00
5675df2a44 Merge pull request #642 from ggtakec/master
Fixed potential atomic violation in S3fsCurl::AddUserAgent - #633
2017-09-17 18:40:34 +09:00
00bc9142c4 Fixed potential atomic violation in S3fsCurl::AddUserAgent - #633 2017-09-17 09:16:05 +00:00
5653ab39fc Merge pull request #639 from andrewgaul/homebrew
Update Homebrew instructions
2017-09-17 15:43:03 +09:00
473dd7c940 Merge pull request #637 from andrewgaul/non-aws-s3
Add blurb about non-Amazon S3 implementations
2017-09-17 15:37:13 +09:00
ee824d52ba Merge pull request #638 from andrewgaul/readme-fixes
Minor fixes to README
2017-09-17 15:31:09 +09:00
7c5fba9890 Merge pull request #636 from swt2c/macos_upload_failures
Fix intermittent upload failures on macOS
2017-09-17 15:23:48 +09:00
f214cb03b2 Update Homebrew instructions
These moved to homebrew-core:

https://github.com/Homebrew/homebrew-core/pull/11283
2017-09-12 18:58:19 -07:00
416c51799b Minor fixes to README 2017-09-12 18:44:27 -07:00
cf6f665f03 Add blurb about non-Amazon S3 implementations
References #629.
2017-09-12 18:09:56 -07:00
20da0e4dd3 Fix intermittent upload failures on macOS
There were multiple problems with the FdManager::GetFreeDiskSpace() function
on macOS:
1) When calling statvfs(), f_frsize should be used instead of f_bsize when
converting available blocks to bytes.  This was causing the free space
calculation to be incorrect.
2) On macOS, fsblkcnt_t is a 32-bit integer.  Thus, when calculating available
disk space, there were frequently overflows.  This caused s3fs to incorrectly
determine that the cache location was out of space in the middle of a transfer
which caused uploads to fail.  Changing this to a uint64_t resolves the
problem.
2017-09-08 15:23:10 -04:00
fa8c417526 Merge pull request #631 from s3fs-fuse/macosx
Merged macosx branch into master branch #601
2017-08-12 00:13:10 +09:00
2c65aec6c8 Merge pull request #630 from ggtakec/macosx
Added travis test on osx for #601
2017-08-11 23:46:51 +09:00
96d8e6d823 Merge remote-tracking branch 'upstream/macosx' into macosx 2017-08-11 14:20:12 +00:00
62b8084300 Added travis test on osx for #601 2017-08-11 14:09:43 +00:00
907aff5de4 Merge pull request #627 from swordsreversed/master
Update README.md
2017-08-02 22:14:08 +09:00
bc09129ec5 Update README.md 2017-08-01 10:20:46 +10:00
cd94f638e2 Update README.md
Add fuse as a dependency!
2017-07-31 21:23:08 +10:00
b1fe419870 Merge pull request #621 from andrewgaul/s3proxy
Upgrade to S3Proxy 1.5.3
2017-07-10 21:13:26 +09:00
98b724391f Upgrade to S3Proxy 1.5.3
Release notes:

https://github.com/andrewgaul/s3proxy/releases/tag/s3proxy-1.5.3
2017-07-09 22:41:39 -07:00
620f6ec616 Merge pull request #611 from ggtakec/master
Fixed clock_gettime build failure on macOS 10.12 Sierra - #600
2017-05-28 19:15:45 +09:00
0c6a3882a2 Fixed clock_gettime build failure on macOS 10.12 Sierra - #600 2017-05-28 10:04:25 +00:00
a08880ae15 Merge pull request #608 from tlevi/chown_nocopy
Fix chown_nocopy losing existing uid/gid if unspecified
2017-05-28 18:36:08 +09:00
f48826dfe9 Merge pull request #609 from tlevi/getgrgid_r
Group permission checks sometimes fail with large number of groups
2017-05-27 11:02:18 +09:00
9c3551478e Merge pull request #606 from andrewgaul/homebrew
Add Homebrew instructions
2017-05-27 11:01:01 +09:00
cc94e1da26 Fix chown_nocopy losing existing uid/gid if unspecified 2017-05-25 16:53:08 +09:30
2b7ea5813c Expand buffer for group information if too small and retry 2017-05-23 10:42:43 +09:30
185192be67 Add Homebrew instructions 2017-05-22 10:12:22 -07:00
ae4caa96a0 Merge pull request #598 from ggtakec/master
Updated ChangeLog and configure.ac for release 1.82
2017-05-14 01:25:34 +09:00
af13ae82c1 Updated ChangeLog and configure.ac for release 1.82 2017-05-13 16:12:46 +00:00
13503c063b Merge pull request #597 from ggtakec/master
Not fallback to HTTP - #596
2017-05-14 01:01:36 +09:00
337da59368 Not fallback to HTTP - #596 2017-05-13 15:47:39 +00:00
b0681246b9 Merge pull request #595 from ggtakec/master
Updated ChangeLog and configure.ac for release 1.81
2017-05-13 20:12:47 +09:00
52853f6b47 Updated ChangeLog and configure.ac for release 1.81 2017-05-13 11:02:54 +00:00
f6eb841a24 Updated ChangeLog and configure.ac for release 1.81 2017-05-13 10:54:54 +00:00
caea087aec Merge pull request #594 from ggtakec/master
Check bucket at public bucket and add nocopyapi option automatically
2017-05-13 17:01:21 +09:00
d2ae14d8b7 Check bucket at public bucket and add nocopyapi option automatically 2017-05-13 07:48:50 +00:00
7115835834 Check bucket at public bucket and add nocopyapi option automatically 2017-05-13 07:35:55 +00:00
551c6acf67 Merge pull request #593 from ggtakec/master
Backward compatible for changing default transport to HTTPS
2017-05-13 16:09:22 +09:00
24df69f688 Backward compatible for changing default transport to HTTPS 2017-05-13 06:47:51 +00:00
23a10dd644 Merge pull request #590 from ggtakec/master
Updated man page for default_acl option - #567
2017-05-09 23:29:04 +09:00
034042f511 Updated man page for default_acl option - #567 2017-05-09 14:18:19 +00:00
465c15ef40 Merge pull request #588 from andrewgaul/https
Default transport to HTTPS
2017-05-09 23:04:57 +09:00
a22675bafd Merge pull request #567 from andrewgaul/default-acl
Do not send ACL unless overridden
2017-05-09 23:03:27 +09:00
0e0ae38f6d Default transport to HTTPS
This protects private data when used over the public Internet.  Users
can opt-in to unencrypted HTTP if they need additional performance on
a local network.  Fixes #282.
2017-05-07 10:59:54 -07:00
7b30d5d15b Do not send canned ACL header when empty string
Some providers such as StorageGRID do not support canned ACLs.
Setting to empty allows callers to omit the header.  References #125.
2017-05-07 10:52:31 -07:00
4a5c9bef89 Merge pull request #587 from ggtakec/master
Changed copyright year format for debian pkg
2017-05-07 20:33:38 +09:00
9d10a5aa70 Changed copyright year format for debian pkg 2017-05-07 11:24:17 +00:00
107757f11d Merge pull request #585 from ggtakec/master
Fixed failure to upload/copy with SSE_C and SSE_KMS
2017-05-07 18:56:17 +09:00
a12e0d5ec4 Fixed failure to upload/copy with SSE_C and SSE_KMS 2017-05-07 09:29:08 +00:00
42cdcbc2dc Merge pull request #583 from ggtakec/master
Updated limit object size in s3fs man page
2017-05-06 13:51:01 +09:00
eef549dac7 Updated limit object size in s3fs man page 2017-05-06 04:34:07 +00:00
c8ee132813 Merge pull request #582 from ggtakec/master
Check errors returned in 200 OK responses for put header request
2017-05-06 11:28:51 +09:00
d07c3f38b7 Check errors returned in 200 OK responses for put header request 2017-05-06 02:15:53 +00:00
73da168b93 Merge pull request #580 from ggtakec/master
Enhanced bucket/path parameter check
2017-05-06 05:13:05 +09:00
1fe0334c08 Enhanced bucket/path parameter check 2017-05-05 19:55:24 +00:00
7d09914f1f Merge pull request #579 from ggtakec/master
Added notsup_compat_dir option
2017-05-06 02:38:36 +09:00
3ac39d61f8 Added notsup_compat_dir option 2017-05-05 17:28:29 +00:00
c5677b4726 Merge pull request #578 from ggtakec/master
Refactored the get_object_attribute function
2017-05-05 19:24:01 +09:00
67685c3d49 Merge pull request #1 from ggtakec/test
Refactored the get_object_attribute function
2017-05-05 19:09:45 +09:00
864e20e1f2 Refactored the get_object_attribute function 2017-05-05 10:02:21 +00:00
51b3183cba Refactored the check_object_access function 2017-05-05 09:51:30 +00:00
f02b1bc352 Merge pull request #576 from ggtakec/master
Added option for complementing lack of stat mode
2017-05-04 13:12:47 +09:00
758b92e823 Added option for complementing lack of stat mode 2017-05-04 03:41:24 +00:00
df0ff3a2fd Merge pull request #556 from orozery/fix_nocache_multipart_upload
fix multipart upload handling without cache
2017-04-16 19:22:15 +09:00
edcf4c6218 Merge pull request #555 from orozery/dont_sign_empty_headers
don't sign empty headers (as they are discarded by libcurl)
2017-04-16 19:16:47 +09:00
28efff5986 Merge pull request #554 from orozery/cache_cleanup
cleanup cache directory when running out of disk space
2017-04-16 19:13:11 +09:00
efba9bcbc1 Merge pull request #553 from orozery/custom_cipher_suite
add TLS cipher suites customization
2017-04-16 19:09:27 +09:00
6bd179c92b Merge pull request #552 from orozery/foreground_threads
switch S3fsMultiCurl to use foreground threads
2017-04-16 19:05:16 +09:00
96764b7410 switch S3fsMultiCurl to use foreground threads 2017-04-09 16:56:49 +03:00
ff3eb1971f Merge branch 'master' into fix_nocache_multipart_upload 2017-04-09 22:13:33 +09:00
94ddcb8d4f Merge pull request #560 from ggtakec/master
Fixed about multipart uploading at no free space related to #509
2017-04-09 14:06:23 +09:00
b4c90d6957 Fixed a bug about multipart uploading at no disk free space related to #509 2017-04-09 04:37:20 +00:00
75b59a7c16 switch S3fsMultiCurl to use foreground threads 2017-04-04 15:32:53 +03:00
3bcca75a88 don't sign empty headers (as they are discarded by libcurl) 2017-04-04 15:24:20 +03:00
79ea1a1561 Merge pull request #558 from ggtakec/master
Fixed a bug in logic about truncating stat cache
2017-04-02 21:02:15 +09:00
f0f61b3b55 Fixed a bug in logic about truncating stat cache 2017-04-02 11:51:58 +00:00
b955391621 Merge pull request #557 from ggtakec/master
Added check_cache_dir_exist option(refixed #347) - #538
2017-04-02 17:32:08 +09:00
8de992d42d Added check_cache_dir_exist option(refixed #347) - #538 2017-04-02 08:17:12 +00:00
fef3fbc225 Added check_cache_dir_exist option(refixed #347) - #538 2017-04-02 08:10:16 +00:00
acb61880b9 Merge pull request #551 from ggtakec/master
Updated stat_cache_expire option description - #545
2017-04-02 16:32:47 +09:00
8ee95ff7ab fix multipart upload handling without cache 2017-04-02 10:27:43 +03:00
95578cad43 cleanup cache directory when running out of disk space 2017-04-02 10:22:12 +03:00
465bbd3729 Updated stat_cache_expire option description - #545 2017-04-02 07:19:16 +00:00
0fa895594e Merge pull request #550 from Vascom/patch-1
Add umount instruction for unplivileged user.
2017-04-02 16:05:40 +09:00
15573cd21e Add umount instruction for unplivileged user.
Ordinary user has no permissions to use umount command, so it is good add fuse unmount instruction in man file.
2017-03-29 11:43:05 +03:00
43df94719b Merge pull request #546 from ggtakec/master
Fixed double initialization of SSL library at foreground
2017-03-20 02:22:19 +09:00
980ba398bc Fixed double initialization of SSL library - #524 2017-03-19 17:11:18 +00:00
0d59ac51c1 Merge pull request #545 from ggtakec/master
Changed base cached time of stat_cache_expire option - #523
2017-03-20 00:40:26 +09:00
523043a2aa Changed base cached time of stat_cache_expire option - #523 2017-03-19 15:19:04 +00:00
277da2c64a Merge pull request #540 from andrewgaul/cppcheck
Address cppcheck 1.77 warnings
2017-03-19 15:27:34 +09:00
03217baa99 Address cppcheck 1.77 warnings 2017-03-06 12:41:08 -08:00
6affefff5b Merge pull request #509 from andrewgaul/mpu
Use server-provided ETag during complete upload
2017-03-06 21:54:51 +09:00
2506fe73fa Merge pull request #539 from andrewgaul/s3proxy
Upgrade to S3Proxy 1.5.2
2017-03-06 21:48:18 +09:00
25a03c370a Upgrade to S3Proxy 1.5.2
Release notes:

https://github.com/andrewgaul/s3proxy/releases/tag/s3proxy-1.5.2
2017-03-02 10:55:24 -08:00
d40da2c68b Merge pull request #520 from ggtakec/master
Added links for eventual consistency in README.md - #515
2017-01-15 17:38:27 +09:00
7d6312ac78 Added links for eventual consistency in README.md - #515 2017-01-15 08:23:55 +00:00
e26c69a327 Merge pull request #517 from hudsantos/master
Update s3fs.1 - removed duplicated word
2017-01-09 10:48:29 +09:00
ff196e4257 Update s3fs.1 2016-12-16 19:16:17 -02:00
19f0d498aa Merge pull request #513 from ggtakec/master
Added issue and PR templates.
2016-12-04 21:33:55 +09:00
97a806447e Added issue and PR templates. 2016-12-04 12:25:11 +00:00
a00af2385b Merge pull request #512 from ggtakec/master
Changed clock_gettime func to s3fs_clock_gettime for homebrew - #468
2016-12-04 19:42:29 +09:00
6fc972972f Changed clock_gettime func to s3fs_clock_gettime for homebrew - #468 2016-12-04 10:31:41 +00:00
989d403b1f Merge remote-tracking branch 'upstream/master' 2016-12-04 08:40:58 +00:00
7b307601b5 Merge pull request #511 from s3fs-fuse/issue#435
Fixed a bug about uploading NULL to some part of the file contents
2016-12-04 17:20:50 +09:00
d731ab3a8e force java to use openjdk7 2016-12-04 08:14:02 +00:00
174d934d52 Initializing java package by update-alternatives 2016-12-04 08:04:33 +00:00
b428f68acf Patched openjdk java path on travis at 12/4/2016 2016-12-04 07:45:28 +00:00
5350e03147 Test configure for what version of java openjdk 2016-12-04 07:23:23 +00:00
28c7888a50 Sepalated install openjdk-7-jdk for checking why travis could not install it. 2016-12-04 07:01:28 +00:00
915a1321c7 Use server-provided ETag during complete upload
This avoids calculating the MD5 locally and enables use with object
stores which do not use MD5 as ETag.
2016-11-23 18:48:57 -08:00
8a11d7bc2f Merge pull request #505 from andrewgaul/spelling
Correct typos
2016-11-20 09:10:27 +09:00
7aae4782d9 Merge pull request #504 from andrewgaul/test
Use describe helper function
2016-11-20 09:10:16 +09:00
aba9e29471 Merge pull request #503 from andrewgaul/mtime-test
Add missing call to mtime test
2016-11-20 09:10:08 +09:00
d375bca0d0 Correct typos 2016-11-19 15:57:41 -08:00
cd0c8599cc Use describe helper function 2016-11-19 15:36:02 -08:00
20878a1618 Add missing call to mtime test 2016-11-19 15:10:41 -08:00
edd0a11fb5 Merge pull request #494 from mapreri/typo
Fix typo s/destroied/destroyed/
2016-11-20 05:53:23 +09:00
5e4bafeab7 Merge pull request #498 from andrewgaul/s3proxy
Upgrade to S3Proxy 1.5.1
2016-11-20 05:44:07 +09:00
67a836223a Merge pull request #495 from driskell/fix_sse_copy
Fix invalid V4 signature on multipart copy requests
2016-11-20 05:43:10 +09:00
7e2d6a3eed Merge remote-tracking branch 'upstream/issue#435' 2016-11-19 20:36:02 +00:00
1ee5a468f4 Merge pull request #502 from ggtakec/issue#435
Fixed issue#435 branch codes for remaining bugs(2)
2016-11-20 05:28:10 +09:00
81e209bdd1 Fixed issue#435 codes 2016-11-19 20:09:35 +00:00
90eda81624 Merge remote-tracking branch 'upstream/issue#435' 2016-11-19 19:52:27 +00:00
cafe6015e3 Upgrade to S3Proxy 1.5.1
Enabled previously broken tests and test with default v4 signer.
Release notes:

https://github.com/andrewgaul/s3proxy/releases/tag/s3proxy-1.5.0
https://github.com/andrewgaul/s3proxy/releases/tag/s3proxy-1.5.1
2016-11-15 23:09:48 -08:00
2492dc60ce Fix invalid V4 signature on multipart copy requests 2016-11-15 23:09:23 -08:00
6f688770fd Fix invalid V4 signature on multipart copy requests 2016-11-13 13:22:00 +00:00
8c0b1d9c5b Fix typo s/destroied/destroyed/ 2016-11-11 23:27:17 +00:00
efde0ec9de Merge pull request #489 from ggtakec/master
Changed headers_t map using nocase compare function - #488
2016-10-23 23:23:31 +09:00
632495374b Chnaged headers_t map using nocase compare function - #488 2016-10-23 14:14:19 +00:00
15b797f3ee Merge pull request #488 from ggtakec/master
Fixed searching Content-Length without case sensitive - #480
2016-10-23 22:42:52 +09:00
a7a64d954a Fixed searching Content-Length without case sensitive - #480 2016-10-23 13:27:01 +00:00
cca217f613 Merge pull request #487 from driskell/debugging
Split header debugging onto multiple lines for easier reading
2016-10-23 21:51:38 +09:00
1a9cf6f66d Fixed searching Content-Length without case sensitive - #480 2016-10-23 12:40:51 +00:00
02d7296210 Split header debugging onto multiple lines for easier reading 2016-10-22 15:11:18 +01:00
a688df813e Fixed a bug at read symlink 2016-10-11 13:32:08 +00:00
164424bc89 Merge branch 'master' into issue#435 2016-10-11 12:13:03 +00:00
f38aaa3d0e Merge pull request #483 from ggtakec/master
Trim symbolic link original path in file.
2016-10-11 19:31:34 +09:00
7fabd18b1f Trim symbolic link original path in file. 2016-10-11 10:22:30 +00:00
5db369d67e Trim symbolic link original path in file. 2016-10-11 10:17:46 +00:00
dba32fdf78 Trim symbolic link original path in file. 2016-10-11 10:06:21 +00:00
716baada22 Testing patch codes for issue#435 2016-10-10 12:16:09 +00:00
1a93897e85 Merge pull request #477 from ggtakec/master
OS-specific correspondence of the extended attribute header
2016-10-02 16:34:55 +09:00
9fd1368611 OS-specific correspondence of the extended attribute header 2016-10-02 07:23:19 +00:00
9f174d7614 Merge pull request #471 from ggtakec/master
Added use_xattr option for #467 and #460
2016-09-19 14:00:20 +09:00
65d52506c4 Added use_xattr option for #467 and #460 2016-09-19 04:28:01 +00:00
a56fe0ea28 Merge pull request #466 from ggtakec/master
Fixed a bug about could not copy file mode from org file
2016-09-11 23:11:22 +09:00
ec110bb0f3 Added small logic in test script for test_chown 2016-09-11 13:41:50 +00:00
232befb52a Added small logic in test script for test_chown 2016-09-11 13:37:53 +00:00
f363c21ff5 Added comments in failure message for test_chown 2016-09-11 13:28:40 +00:00
1a96f40a10 Fixed a bug about could not copy file mode from org file 2016-09-11 13:09:23 +00:00
6be3236b28 Merge pull request #451 from kasbah/patch-1
Correct path in README
2016-07-24 17:32:35 +09:00
ccefd835d0 Merge pull request #454 from ggtakec/master
Changed for accepting mount options compatible with mtab - #449
2016-07-24 17:31:45 +09:00
1ddc14d59d Changed for accepting mount options compatible with mtab - #449 2016-07-24 08:17:58 +00:00
87f617374a Merge pull request #449 from treestem/mountopt
Accept mount options compatible with mtab
2016-07-24 16:48:33 +09:00
b76fc350b0 Merge pull request #447 from dsulli99/master
added fuse package for mounting via /etc/fstab, fixes #417
2016-07-18 22:25:30 +09:00
4deb6fdd84 added fuse package for mounting via /etc/fstab, fixes #417 2016-07-15 06:12:47 -05:00
2d5be2157a Correct path in README 2016-07-14 16:55:03 +01:00
a19206cf0f Accept mount arguments compatible with mtab
Using "mount -a" fails for already-mounted s3fs directories,
because s3fs mount arguments don't match the form in /etc/mtab.
Calling "mount -a" should quietly succeed when a directory is
already mounted.

To fix this, accept mount commands of the form:

s3fs s3fs /srv/object-store -o bucket=mybucket

or in /etc/fstab form:

s3fs  /srv/object-store  fuse.s3fs  bucket=mybucket 0 0

This matches the form in /etc/mtab and allows "mount -a" to
work properly.
2016-07-13 17:23:33 -04:00
0f9428ad5a Add mirror file logic for removing cache file 2016-07-13 17:23:32 -04:00
d748b333ee Merge pull request #444 from ggtakec/master
Add mirror file logic for removing cache file
2016-07-03 13:07:59 +09:00
e8a8019a71 Add mirror file logic for removing cache file 2016-07-03 03:37:08 +00:00
e8680b485d Merge pull request #443 from tlevi/master
Fix for leaks during stat cache entry expiry / truncation (#340)
2016-07-03 12:24:41 +09:00
ab4b92074c Fix cppcheck complaint 2016-06-30 11:51:25 +09:30
d57c12d3c3 Possible fix for leaks during entry expiry / truncation (#340) 2016-06-28 15:01:14 +09:30
676b2090fb Merge pull request #440 from ggtakec/master
Handled all curl error without exiting process - #437
2016-06-27 20:04:29 +09:00
6005929a96 Handled all curl error without exiting process - #437 2016-06-27 10:38:49 +00:00
49ffaa1d94 Merge pull request #432 from andrewgaul/create-bucket-location
Include location constraint when creating bucket
2016-06-26 09:39:47 +09:00
9fb3fd1a4d Merge pull request #433 from andrewgaul/typo
Correct search and replace typo
2016-06-14 21:45:01 +09:00
28b2b5cac3 Merge pull request #431 from mapreri/typo
fix typo s/controll/control/
2016-06-14 21:43:37 +09:00
320b8e1171 Include location constraint when creating bucket
This allows creating buckets in non-default regions.  Also improve
do_create_bucket error handling.
2016-06-13 10:35:37 -07:00
95cb5d201f Correct search and replace typo 2016-06-13 10:25:33 -07:00
880708ab5f fix typo s/controll/control/ 2016-06-12 15:02:40 +00:00
113 changed files with 38109 additions and 14761 deletions

83
.clang-tidy Normal file
View File

@ -0,0 +1,83 @@
WarningsAsErrors: '*'
Checks: '
*,
-abseil-*,
-altera-*,
-android-*,
-boost-*,
-bugprone-assignment-in-if-condition,
-bugprone-branch-clone,
-bugprone-easily-swappable-parameters,
-bugprone-implicit-widening-of-multiplication-result,
-bugprone-macro-parentheses,
-bugprone-narrowing-conversions,
-bugprone-unhandled-self-assignment,
-cert-dcl50-cpp,
-cert-env33-c,
-cert-err33-c,
-cert-err58-cpp,
-clang-analyzer-security.insecureAPI.strcpy,
-clang-analyzer-unix.BlockInCriticalSection,
-concurrency-mt-unsafe,
-cppcoreguidelines-avoid-c-arrays,
-cppcoreguidelines-avoid-do-while,
-cppcoreguidelines-avoid-magic-numbers,
-cppcoreguidelines-avoid-non-const-global-variables,
-cppcoreguidelines-init-variables,
-cppcoreguidelines-macro-usage,
-cppcoreguidelines-no-malloc,
-cppcoreguidelines-owning-memory,
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
-cppcoreguidelines-pro-bounds-constant-array-index,
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
-cppcoreguidelines-pro-type-member-init,
-cppcoreguidelines-pro-type-reinterpret-cast,
-cppcoreguidelines-pro-type-union-access,
-cppcoreguidelines-pro-type-vararg,
-cppcoreguidelines-special-member-functions,
-fuchsia-*,
-google-build-using-namespace,
-google-readability-function-size,
-google-readability-todo,
-google-runtime-int,
-google-runtime-references,
-hicpp-*,
-llvm-*,
-llvmlibc-*,
-misc-const-correctness,
-misc-include-cleaner,
-misc-no-recursion,
-misc-non-private-member-variables-in-classes,
-misc-redundant-expression,
-misc-unused-parameters,
-misc-use-anonymous-namespace,
-misc-use-internal-linkage,
-modernize-avoid-c-arrays,
-modernize-loop-convert,
-modernize-use-nodiscard,
-modernize-raw-string-literal,
-modernize-return-braced-init-list,
-modernize-use-default-member-init,
-modernize-use-trailing-return-type,
-modernize-use-using,
-performance-avoid-endl,
-performance-no-int-to-ptr,
-readability-avoid-nested-conditional-operator,
-readability-braces-around-statements,
-readability-else-after-return,
-readability-function-cognitive-complexity,
-readability-function-size,
-readability-identifier-length,
-readability-inconsistent-declaration-parameter-name,
-readability-isolate-declaration,
-readability-magic-numbers,
-readability-math-missing-parentheses,
-readability-named-parameter,
-readability-redundant-access-specifiers,
-readability-redundant-declaration,
-readability-simplify-boolean-expr,
-readability-suspicious-call-argument'
CheckOptions:
cppcoreguidelines-narrowing-conversions.WarnOnEquivalentBitWidth: 'false'
readability-implicit-bool-conversion.AllowIntegerConditions: 'true'
readability-implicit-bool-conversion.AllowPointerConditions: 'true'

32
.gitattributes vendored Normal file
View File

@ -0,0 +1,32 @@
#
# s3fs - FUSE-based file system backed by Amazon S3
#
# Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
#
# 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.
#
* text eol=lf
*.png binary
#
# Local variables:
# tab-width: 4
# c-basic-offset: 4
# End:
# vim600: noet sw=4 ts=4 fdm=marker
# vim<600: noet sw=4 ts=4
#

View File

@ -0,0 +1,16 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: 'feature request'
assignees: ''
---
### Feature request
<!-- -------------------------------------------------------------
Please let us know your ideas, such as features you want to improve,
features to add, etc.
And list any related Issue or Pull Request numbers.
-------------------------------------------------------------- -->

View File

@ -0,0 +1,49 @@
---
name: Support request (Including bug reports)
about: Request support for usage, bugs, etc.
title: ''
labels: ''
assignees: ''
---
<!-- --------------------------------------------------------------------------
The following information is very important in order to help us to help you.
Omission of the following details may delay your support request or receive no
attention at all.
--------------------------------------------------------------------------- -->
### Additional Information
#### Version of s3fs being used (`s3fs --version`)
<!-- example: V1.91 (commit:b19262a) -->
#### Version of fuse being used (`pkg-config --modversion fuse`, `rpm -qi fuse` or `dpkg -s fuse`)
<!-- example: 2.9.2 -->
#### Provider (`AWS`, `OVH`, `Hetzner`, `iDrive E2`, ...)
<!-- example: AWS -->
#### Kernel information (`uname -r`)
<!-- example: 5.10.96-90.460.amzn2.x86_64 -->
#### GNU/Linux Distribution, if applicable (`cat /etc/os-release`)
<!-- command result -->
#### How to run s3fs, if applicable
<!-- Describe the s3fs "command line" or "/etc/fstab" entry used. -->
[] command line
[] /etc/fstab
<!-- Executed command line or /etc/fastab entry -->
```
```
#### s3fs syslog messages (`grep s3fs /var/log/syslog`, `journalctl | grep s3fs`, or `s3fs outputs`)
<!-- if you execute s3fs with dbglevel, curldbg option, you can get detail debug messages. -->
```
```
### Details about issue
<!-- Please describe the content of the issue in detail. -->

11
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,11 @@
<!-- --------------------------------------------------------------------------
Please describe the purpose of the pull request(such as resolving the issue)
and what the fix/update is.
--------------------------------------------------------------------------- -->
### Relevant Issue (if applicable)
<!-- If there are Issues related to this PullRequest, please list it. -->
### Details
<!-- Please describe the details of PullRequest. -->

316
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,316 @@
#
# s3fs - FUSE-based file system backed by Amazon S3
#
# Copyright(C) 2007 Takeshi Nakatani <ggtakec.com>
#
# 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.
#
name: s3fs-fuse CI
on:
push:
pull_request:
#
# CRON event is fired on every sunday (UTC).
#
schedule:
- cron: '0 0 * * 0'
#
# Jobs
#
jobs:
Linux:
runs-on: ubuntu-latest
#
# build matrix for containers
#
strategy:
#
# do not stop jobs automatically if any of the jobs fail
#
fail-fast: false
#
# matrix for containers
#
matrix:
container:
- ubuntu:25.10
- ubuntu:24.04
- ubuntu:22.04
- debian:trixie
- debian:bookworm
- debian:bullseye
- rockylinux/rockylinux:10
- rockylinux/rockylinux:9
- rockylinux/rockylinux:8
- fedora:43
- fedora:42
- opensuse/leap:15
- opensuse/leap:16.0
- alpine:3.22
container:
image: ${{ matrix.container }}
options: "--privileged --cap-add SYS_ADMIN --device /dev/fuse"
env:
# [NOTE]
# Installation special environment variables for debian and ubuntu.
#
DEBIAN_FRONTEND: noninteractive
steps:
# [NOTE]
# On openSUSE, tar and gzip must be installed before action/checkout.
#
- name: Install openSUSE packages before checkout
if: matrix.container == 'opensuse/leap:15' || matrix.container == 'opensuse/leap:16.0'
run: zypper install -y tar gzip
- name: Install Alpine packages before checkout
if: matrix.container == 'alpine:3.22'
run: apk add --no-progress --no-cache bash
- name: Checkout source code
uses: actions/checkout@v4
# [NOTE]
# Matters that depend on OS:VERSION are determined and executed in the following script.
# Please note that the option to configure (CONFIGURE_OPTIONS) is set in the environment variable.
#
- name: Install packages
run: |
.github/workflows/linux-ci-helper.sh ${{ matrix.container }}
- name: Build
run: |
./autogen.sh
/bin/sh -c "./configure ${CONFIGURE_OPTIONS}"
make --jobs=$(nproc)
- name: Test suite
run: |
make check -C src
make ALL_TESTS=1 check -C test || (test/filter-suite-log.sh test/test-suite.log; exit 1)
# [NOTE]
# Using macos-fuse-t
# This product(package) is a workaround for osxfuse which required an OS reboot(macos 11 and later).
# see. https://github.com/macos-fuse-t/fuse-t
# About osxfuse
# This job doesn't work with GitHub Actions using macOS 11+ because "load_osxfuse" returns
# "exit code = 1".(requires OS reboot)
#
macos-14:
runs-on: macos-14
# [NOTE]
# In macos-14 (and maybe later), the location of the CA certificate is different and you need to specify it.
# We give the CA path as an environment variable.
#
env:
CURL_CA_BUNDLE: "/opt/homebrew/etc/ca-certificates/cert.pem"
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Brew tap
run: |
TAPS="$(brew --repository)/Library/Taps";
if [ -e "$TAPS/caskroom/homebrew-cask" ]; then rm -rf "$TAPS/caskroom/homebrew-cask"; fi;
HOMEBREW_NO_AUTO_UPDATE=1 brew tap homebrew/homebrew-cask
HOMEBREW_NO_AUTO_UPDATE=1 brew tap macos-fuse-t/homebrew-cask
- name: Install fuse-t
run: |
if [ ! -d /usr/local/include ]; then sudo mkdir -p /usr/local/include; echo "Created /usr/local/include directory"; fi
HOMEBREW_NO_AUTO_UPDATE=1 brew install fuse-t
- name: Install brew other packages
run: |
S3FS_BREW_PACKAGES='automake cppcheck python3 coreutils gnu-sed shellcheck jq';
for s3fs_brew_pkg in ${S3FS_BREW_PACKAGES}; do
if brew list | grep -q ${s3fs_brew_pkg}; then if brew outdated | grep -q ${s3fs_brew_pkg}; then HOMEBREW_NO_AUTO_UPDATE=1 brew upgrade ${s3fs_brew_pkg}; fi; else HOMEBREW_NO_AUTO_UPDATE=1 brew install ${s3fs_brew_pkg}; fi
done
- name: Build
run: |
./autogen.sh
PKG_CONFIG_PATH=/usr/local/opt/curl/lib/pkgconfig:/usr/local/opt/openssl/lib/pkgconfig ./configure
make --jobs=$(sysctl -n hw.ncpu)
- name: Cppcheck
run: make cppcheck
- name: Shellcheck
run: make shellcheck
- name: Test suite
run: |
make check -C src
make ALL_TESTS=1 check -C test || (test/filter-suite-log.sh test/test-suite.log; exit 1)
MemoryTest:
runs-on: ubuntu-latest
#
# build matrix for containers
#
strategy:
#
# do not stop jobs automatically if any of the jobs fail
#
fail-fast: false
#
# matrix for type of checking
#
# [NOTE]
# Currently following test is not supported:
# - sanitize_memory : Future support planned
#
matrix:
checktype:
- glibc_debug
- sanitize_address
- sanitize_others
- sanitize_thread
- thread_safety
- valgrind
container:
image: fedora:43
options: "--privileged --cap-add SYS_ADMIN --device /dev/fuse"
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Install packages
run: |
.github/workflows/linux-ci-helper.sh fedora:43
- name: Install clang
run: |
dnf install -y \
clang \
libcxx \
libcxx-devel
- name: Install Valgrind
if: matrix.checktype == 'valgrind'
run: dnf install -y valgrind
#
# Set CXX/CXXFLAGS and Variables for test
#
- name: Set variables
run: |
COMMON_CXXFLAGS='-g -Wno-cpp'
{
if [ "${{ matrix.checktype }}" = "glibc_debug" ]; then
echo "CXXFLAGS=${COMMON_CXXFLAGS} -O0 -D_GLIBCXX_DEBUG"
elif [ "${{ matrix.checktype }}" = "sanitize_address" ]; then
echo 'CXX=clang++'
echo "CXXFLAGS=${COMMON_CXXFLAGS} -O0 -fsanitize=address -fsanitize-address-use-after-scope"
echo 'ASAN_OPTIONS=detect_leaks=1,detect_stack_use_after_return=1'
elif [ "${{ matrix.checktype }}" = "sanitize_memory" ]; then
echo 'CXX=clang++'
echo "CXXFLAGS=${COMMON_CXXFLAGS} -O0 -fsanitize=memory"
elif [ "${{ matrix.checktype }}" = "sanitize_thread" ]; then
echo 'CXX=clang++'
echo "CXXFLAGS=${COMMON_CXXFLAGS} -O0 -fsanitize=thread"
echo 'TSAN_OPTIONS=halt_on_error=1'
# [NOTE]
# Set this to avoid following error when running configure.
# "FATAL: ThreadSanitizer: unexpected memory mapping"
sysctl vm.mmap_rnd_bits=28
elif [ "${{ matrix.checktype }}" = "sanitize_others" ]; then
echo 'CXX=clang++'
echo "CXXFLAGS=${COMMON_CXXFLAGS} -O1 -fsanitize=undefined,implicit-conversion,local-bounds,unsigned-integer-overflow"
elif [ "${{ matrix.checktype }}" = "thread_safety" ]; then
echo 'CXX=clang++'
echo "CXXFLAGS=${COMMON_CXXFLAGS} -O1 -Wthread-safety -Wthread-safety-beta -stdlib=libc++ -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS -Werror"
echo 'LDFLAGS=-DCLANG_DEFAULT_LINKER=lld'
elif [ "${{ matrix.checktype }}" = "valgrind" ]; then
echo "CXXFLAGS=${COMMON_CXXFLAGS} -O1"
echo 'VALGRIND="--leak-check=full --error-exitcode=1"'
echo 'RETRIES=100'
echo 'S3_URL=http://127.0.0.1:8081'
fi
} >> "$GITHUB_ENV"
- name: Build
run: |
./autogen.sh
/bin/sh -c "CXX=${CXX} CXXFLAGS=\"${CXXFLAGS}\" LDFLAGS=\"${LDFLAGS}\" ./configure --prefix=/usr --with-openssl"
make --jobs=$(nproc)
- name: Test suite
run: |
/bin/sh -c "ALL_TESTS=1 ASAN_OPTIONS=${ASAN_OPTIONS} TSAN_OPTIONS=${TSAN_OPTIONS} VALGRIND=${VALGRIND} RETRIES=${RETRIES} make check -C test || (test/filter-suite-log.sh test/test-suite.log; exit 1)"
static-checks:
runs-on: ubuntu-latest
container:
image: fedora:42
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Install packages
run: |
.github/workflows/linux-ci-helper.sh fedora:42
- name: Install extra packages
run: |
dnf install -y \
clang-tools-extra \
cppcheck \
python3 \
ShellCheck
- name: Build
run: |
./autogen.sh
/bin/sh -c "./configure ${CONFIGURE_OPTIONS}"
make --jobs=$(nproc)
- name: clang-tidy
run: |
make clang-tidy
- name: Cppcheck
run: |
make cppcheck
- name: Shellcheck
run: |
make shellcheck
#
# Local variables:
# tab-width: 4
# c-basic-offset: 4
# End:
# vim600: expandtab sw=4 ts=4 fdm=marker
# vim<600: expandtab sw=4 ts=4
#

417
.github/workflows/linux-ci-helper.sh vendored Executable file
View File

@ -0,0 +1,417 @@
#!/bin/bash
#
# s3fs - FUSE-based file system backed by Amazon S3
#
# Copyright(C) 2007 Takeshi Nakatani <ggtakec.com>
#
# 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.
#
# [NOTE]
# Since bash is not present in some Runner containers, this script
# runs in sh.
# pipefail etc. are not native variables of sh. It exists in bash's
# sh compatibility mode, but doesn't work in sh compatibility mode
# of ash such as alpine.
# However, it's not fatal that pipefail doesn't work for this script.
#
set -o errexit
set -o nounset
#set -o pipefail
#-----------------------------------------------------------
# Common variables
#-----------------------------------------------------------
PRGNAME=$(basename "$0")
echo "${PRGNAME} [INFO] Start Linux helper for installing packages."
#-----------------------------------------------------------
# Parameter check
#-----------------------------------------------------------
#
# Usage: ${PRGNAME} "OS:VERSION"
#
if [ $# -ne 1 ]; then
echo "${PRGNAME} [ERROR] No container name options specified."
fi
#-----------------------------------------------------------
# Container OS variables
#-----------------------------------------------------------
CONTAINER_FULLNAME=$1
# shellcheck disable=SC2034
CONTAINER_OSNAME=$(echo "${CONTAINER_FULLNAME}" | cut -d: -f1)
# shellcheck disable=SC2034
CONTAINER_OSVERSION=$(echo "${CONTAINER_FULLNAME}" | cut -d: -f2)
CURL_DIRECT_VERSION="v8.11.0"
CURL_DIRECT_URL="https://github.com/moparisthebest/static-curl/releases/download/${CURL_DIRECT_VERSION}/curl-$(uname -m | sed -e s/x86_64/amd64/)"
CURL_HASH_X86_64="d18aa1f4e03b50b649491ca2c401cd8c5e89e72be91ff758952ad2ab5a83135d"
CURL_HASH_AARCH64="1b050abd1669f9a2ac29b34eb022cdeafb271dce5a4fb57d8ef8fadff6d7be1f"
#-----------------------------------------------------------
# Parameters for configure(set environments)
#-----------------------------------------------------------
CXX="g++"
CXXFLAGS="-O"
LDFLAGS=""
CONFIGURE_OPTIONS="--prefix=/usr --with-openssl"
#-----------------------------------------------------------
# OS dependent variables
#-----------------------------------------------------------
#
# Default values
#
PACKAGE_ENABLE_REPO_OPTIONS=""
PACKAGE_INSTALL_ADDITIONAL_OPTIONS=""
CURL_DIRECT_INSTALL=0
if [ "${CONTAINER_FULLNAME}" = "ubuntu:25.10" ] ||
[ "${CONTAINER_FULLNAME}" = "ubuntu:24.04" ]; then
PACKAGE_MANAGER_BIN="apt-get"
PACKAGE_UPDATE_OPTIONS="update -y -qq"
PACKAGE_INSTALL_OPTIONS="install -y"
INSTALL_PACKAGES=(
attr
autoconf
autotools-dev
build-essential
curl
fuse
g++
git
jq
libcurl4-openssl-dev
libfuse-dev
libssl-dev
libtool
libxml2-dev
locales-all
mailcap
openjdk-21-jre-headless
pkg-config
)
elif [ "${CONTAINER_FULLNAME}" = "ubuntu:22.04" ]; then
PACKAGE_MANAGER_BIN="apt-get"
PACKAGE_UPDATE_OPTIONS="update -y -qq"
PACKAGE_INSTALL_OPTIONS="install -y"
INSTALL_PACKAGES=(
attr
autoconf
autotools-dev
build-essential
curl
fuse
g++
git
jq
libcurl4-openssl-dev
libfuse-dev
libssl-dev
libtool
libxml2-dev
locales-all
mime-support
openjdk-21-jre-headless
pkg-config
)
CURL_DIRECT_INSTALL=1
elif [ "${CONTAINER_FULLNAME}" = "debian:trixie" ]; then
PACKAGE_MANAGER_BIN="apt-get"
PACKAGE_UPDATE_OPTIONS="update -y -qq"
PACKAGE_INSTALL_OPTIONS="install -y"
INSTALL_PACKAGES=(
attr
autoconf
autotools-dev
build-essential
curl
fuse
g++
git
jq
libcurl4-openssl-dev
libfuse-dev
libssl-dev
libtool
libxml2-dev
locales-all
mailcap
openjdk-21-jre-headless
pkg-config
procps
)
elif [ "${CONTAINER_FULLNAME}" = "debian:bookworm" ] ||
[ "${CONTAINER_FULLNAME}" = "debian:bullseye" ]; then
PACKAGE_MANAGER_BIN="apt-get"
PACKAGE_UPDATE_OPTIONS="update -y -qq"
PACKAGE_INSTALL_OPTIONS="install -y"
INSTALL_PACKAGES=(
attr
autoconf
autotools-dev
build-essential
curl
fuse
g++
git
jq
libcurl4-openssl-dev
libfuse-dev
libssl-dev
libtool
libxml2-dev
locales-all
mime-support
openjdk-17-jre-headless
pkg-config
procps
)
CURL_DIRECT_INSTALL=1
elif [ "${CONTAINER_FULLNAME}" = "rockylinux/rockylinux:10" ] ||
[ "${CONTAINER_FULLNAME}" = "rockylinux/rockylinux:9" ]; then
PACKAGE_MANAGER_BIN="dnf"
PACKAGE_UPDATE_OPTIONS="update -y -qq"
PACKAGE_INSTALL_OPTIONS="install -y"
PACKAGE_ENABLE_REPO_OPTIONS="--enablerepo=crb"
# [NOTE]
# Rocky Linux 9/10 (or CentOS Stream 9/10) images may have curl installation issues that
# conflict with the curl-minimal package.
#
PACKAGE_INSTALL_ADDITIONAL_OPTIONS="--allowerasing"
INSTALL_PACKAGES=(
attr
automake
curl
curl-devel
diffutils
fuse
fuse-devel
gcc
gcc-c++
git
glibc-langpack-en
java-21-openjdk-headless
jq
libstdc++-devel
libxml2-devel
mailcap
make
openssl
openssl-devel
perl-Test-Harness
procps
xz
)
CURL_DIRECT_INSTALL=1
elif [ "${CONTAINER_FULLNAME}" = "rockylinux/rockylinux:8" ]; then
PACKAGE_MANAGER_BIN="dnf"
PACKAGE_UPDATE_OPTIONS="update -y -qq"
PACKAGE_INSTALL_OPTIONS="install -y"
INSTALL_PACKAGES=(
attr
automake
curl
curl-devel
diffutils
fuse
fuse-devel
gcc
gcc-c++
git
glibc-langpack-en
java-21-openjdk-headless
jq
libstdc++-devel
libxml2-devel
mailcap
make
openssl
openssl-devel
perl-Test-Harness
)
CURL_DIRECT_INSTALL=1
elif [ "${CONTAINER_FULLNAME}" = "fedora:43" ] ||
[ "${CONTAINER_FULLNAME}" = "fedora:42" ]; then
PACKAGE_MANAGER_BIN="dnf"
PACKAGE_UPDATE_OPTIONS="update -y -qq"
PACKAGE_INSTALL_OPTIONS="install -y"
INSTALL_PACKAGES=(
attr
automake
curl
curl-devel
diffutils
fuse
fuse-devel
gawk
gcc
gcc-c++
git
glibc-langpack-en
java-latest-openjdk-headless
jq
libstdc++-devel
libxml2-devel
mailcap
make
openssl
openssl-devel
perl-Test-Harness
procps
)
elif [ "${CONTAINER_FULLNAME}" = "opensuse/leap:15" ] ||
[ "${CONTAINER_FULLNAME}" = "opensuse/leap:16.0" ]; then
PACKAGE_MANAGER_BIN="zypper"
PACKAGE_UPDATE_OPTIONS="refresh"
PACKAGE_INSTALL_OPTIONS="install -y"
INSTALL_PACKAGES=(
attr
automake
curl
curl-devel
diffutils
fuse
fuse-devel
gcc-c++
java-21-openjdk-headless
jq
libxml2-devel
make
openssl
openssl-devel
procps
python3
)
elif [ "${CONTAINER_FULLNAME}" = "alpine:3.22" ]; then
PACKAGE_MANAGER_BIN="apk"
PACKAGE_UPDATE_OPTIONS="update --no-progress"
PACKAGE_INSTALL_OPTIONS="add --no-progress --no-cache"
INSTALL_PACKAGES=(
attr
autoconf
automake
coreutils
curl
curl-dev
fuse-dev
g++
git
jq
libtool
libxml2-dev
mailcap
make
openjdk21
openssl
perl-test-harness-utils
procps
sed
)
else
echo "No container configured for: ${CONTAINER_FULLNAME}"
exit 1
fi
#-----------------------------------------------------------
# Install
#-----------------------------------------------------------
#
# Update packages (ex. apt-get update -y -qq)
#
echo "${PRGNAME} [INFO] Updates."
/bin/sh -c "${PACKAGE_MANAGER_BIN} ${PACKAGE_UPDATE_OPTIONS}"
#
# Install packages
#
echo "${PRGNAME} [INFO] Install packages."
/bin/sh -c "${PACKAGE_MANAGER_BIN} ${PACKAGE_ENABLE_REPO_OPTIONS} ${PACKAGE_INSTALL_OPTIONS} ${PACKAGE_INSTALL_ADDITIONAL_OPTIONS} ${INSTALL_PACKAGES[*]}"
# Check Java version
java -version
# Install newer curl for older distributions
if [ "${CURL_DIRECT_INSTALL}" -eq 1 ]; then
echo "${PRGNAME} [INFO] Install newer curl package."
curl --fail --location --silent --output "/tmp/curl" "${CURL_DIRECT_URL}"
case "$(uname -m)" in
x86_64) curl_hash="$CURL_HASH_X86_64" ;;
aarch64) curl_hash="$CURL_HASH_AARCH64" ;;
*) exit 1 ;;
esac
echo "$curl_hash" "/tmp/curl" | sha256sum --check
mv "/tmp/curl" "/usr/local/bin/curl"
chmod +x "/usr/local/bin/curl"
# Rocky Linux 8 and 9 have a different certificate path
if [ ! -f /etc/ssl/certs/ca-certificates.crt ]; then
ln -s /etc/pki/tls/certs/ca-bundle.crt /etc/ssl/certs/ca-certificates.crt
fi
fi
# Check curl version
curl --version
#-----------------------------------------------------------
# Set environment for configure
#-----------------------------------------------------------
echo "${PRGNAME} [INFO] Set environment for configure options"
cat << EOF >> "${GITHUB_ENV}"
CXX=${CXX}
CXXFLAGS=${CXXFLAGS}
LDFLAGS=${LDFLAGS}
CONFIGURE_OPTIONS=${CONFIGURE_OPTIONS}
EOF
echo "${PRGNAME} [INFO] Finish Linux helper for installing packages."
exit 0
#
# Local variables:
# tab-width: 4
# c-basic-offset: 4
# End:
# vim600: expandtab sw=4 ts=4 fdm=marker
# vim<600: expandtab sw=4 ts=4
#

140
.gitignore vendored
View File

@ -1,30 +1,112 @@
#
# s3fs - FUSE-based file system backed by Amazon S3
#
# Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
#
# 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.
#
#
# Compiled Object files
#
*.slo
*.lo
*.o
/Makefile
/Makefile.in
/aclocal.m4
/autom4te.cache/
/config.guess
/config.log
/config.status
/config.sub
/stamp-h1
/config.h
/config.h.in
/configure
/depcomp
/test-driver
/compile
/doc/Makefile
/doc/Makefile.in
/install-sh
/missing
/src/.deps/
/src/Makefile
/src/Makefile.in
/src/s3fs
/src/test_*
/test/.deps/
/test/Makefile
/test/Makefile.in
/test/*.log
/default_commit_hash
*.Po
*.Plo
#
# autotools/automake
#
aclocal.m4
autom4te.cache
autoscan.log
config.guess
config.h
config.h.in
config.h.in~
config.log
config.status
config.sub
configure
configure.scan
configure.ac~
depcomp
install-sh
libtool
ltmain.sh
m4
m4/*
missing
stamp-h1
Makefile
Makefile.in
test-driver
compile
missing
#
# man page
#
doc/man/s3fs.1
#
# object directories
#
.deps
.libs
*/.deps
*/.deps/*
*/.libs
*/.libs/*
#
# each directories
#
*.log
*.trs
default_commit_hash
src/s3fs
src/test_curl_util
src/test_page_list
src/test_string_util
test/chaos-http-proxy-*
test/junk_data
test/pjdfstest
test/pjd-pjdfstest-*
test/s3proxy-*
test/write_multiblock
test/mknod_test
test/truncate_read_file
test/cr_filename
#
# Windows ports
#
*.dll
*.exe
fuse.pc
WinFsp/
bin/
#
# Local variables:
# tab-width: 4
# c-basic-offset: 4
# End:
# vim600: noet sw=4 ts=4 fdm=marker
# vim<600: noet sw=4 ts=4
#

View File

@ -1,16 +0,0 @@
language: cpp
sudo: required
dist: trusty
cache: apt
before_install:
- sudo apt-get update -qq
- sudo apt-get install -qq cppcheck libfuse-dev openjdk-7-jdk
script:
- ./autogen.sh
- ./configure
- make
- make cppcheck
- make check -C src
- modprobe fuse
- make check -C test
- cat test/test-suite.log

View File

@ -17,3 +17,7 @@ Bugfixes, performance and other improvements.
5. Takeshi Nakatani <ggtakec@gmail.com>
Bugfixes, performance and other improvements.
6. Andrew Gaul <gaul@gaul.org>
Bugfixes, performance and other improvements.

116
COMPILATION.md Normal file
View File

@ -0,0 +1,116 @@
# Compilation from source code
These are generic instructions should work on almost any GNU/Linux, macOS, BSD, or similar.
If you want specific instructions for some distributions, check the [wiki](https://github.com/s3fs-fuse/s3fs-fuse/wiki/Installation-Notes).
Keep in mind using the pre-built packages when available.
## Compilation on Linux
### Ensure your system satisfies build and runtime dependencies for:
* fuse >= 2.8.4
* automake
* gcc-c++
* make
* libcurl
* libxml2
* openssl/gnutls/nss
* Please prepare the library according to the OS on which you will compile.
* It is necessary to match the library used by libcurl.
* Install the OpenSSL, GnuTLS or NSS devel package.
* mime.types (the package providing depends on the OS)
* s3fs tries to detect `/etc/mime.types` as default regardless of the OS
* Else s3fs tries to detect `/etc/apache2/mime.types` if OS is macOS
* s3fs exits with an error if these files are not exist
* Alternatively, you can set mime.types file path with `mime` option without detecting these default files
* pkg-config (or your OS equivalent)
* NOTE
If you have any trouble about details on required packages, see `INSTALL_PACKAGES` in [linux-ci-helper.sh](https://github.com/s3fs-fuse/s3fs-fuse/blob/master/.github/workflows/linux-ci-helper.sh).
### Then compile from master via the following commands:
1. Clone the source code:
```sh
git clone https://github.com/s3fs-fuse/s3fs-fuse.git
```
2. Configuration:
```sh
cd s3fs-fuse
./autogen.sh
./configure
```
Depending on the TLS library (OpenSSL/GnuTLS/NSS), add `--with-openssl`, `--with-gnutls` or `--with-nss` when executing `configure`. (If omitted, it is equivalent to `--with-openssl`.)
3. Building:
```sh
make
```
4. Installing:
```sh
sudo make install
```
### NOTE - The required libraries/components required to run s3fs are:
* fuse >= 2.8.4
* libcurl
* libxml2
* openssl/gnutls/nss
* mime.types (the package providing depends on the OS)
## Compilation on Windows (using MSYS2)
On Windows, use [MSYS2](https://www.msys2.org/) to compile for itself.
1. Install [WinFsp](https://github.com/billziss-gh/winfsp) to your machine. Note it should be installed with developer mode to include header files.
2. Install dependencies onto MSYS2:
```sh
pacman -S git autoconf automake gcc make pkg-config openssl-devel libcurl-devel libxml2-devel libzstd-devel
```
3. Clone this repository, then change directory into the cloned one.
4. Copy WinFsp files to the directory:
```sh
cp -r "/c/Program Files (x86)/WinFsp" "./WinFsp"
```
5. Write `fuse.pc` to resolve the package correctly:
```sh
cat > ./fuse.pc << 'EOS'
arch=x64
prefix=${pcfiledir}/WinFsp
incdir=${prefix}/inc/fuse
implib=${prefix}/bin/winfsp-${arch}.dll
Name: fuse
Description: WinFsp FUSE compatible API
Version: 2.8.4
URL: http://www.secfs.net/winfsp/
Libs: "${implib}"
Cflags: -I"${incdir}"
EOS
```
6. Compile using the command line:
```sh
./autogen.sh
PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$(pwd)" ./configure
make CXXFLAGS="-I/usr/include"
```
7. Copy binary files to distribute at one place:
```sh
mkdir ./bin
cp ./src/s3fs.exe ./bin/
cp ./WinFsp/bin/winfsp-x64.dll ./bin/
cp /usr/bin/msys-*.dll ./bin/
```
8. Distribute these files.

434
ChangeLog
View File

@ -1,6 +1,363 @@
ChangeLog for S3FS
ChangeLog for S3FS
------------------
Version 1.95 -- 25 Oct, 2024 (major changes only)
#2424 - Add ipresolve option to select IPv4- or IPv6-only
#2443 - Retry request on HTTP 429 error
#2448 - Changed s3fs logo
#2455 - Fix deadlock in FdManager::ChangeEntityToTempPath
#2487 - #2492 - #2493 - Enable static lock checking and fix locking errors
#2506 - #2517 - Fix Windows compilation
#2515 - Fix FreeBSD support
#2532 - Fix use-after-free in FdManager::ChangeEntityToTempPath
Version 1.94 -- 23 Feb, 2024 (major changes only)
#2409 - Fixed a bug that mounting with ksmid specified to fail
#2404 - Fixed ordering problem between fdatasync and flush
#2399 - Fixed ListBucket/IAM edge cases
#2376 - Corrected list_bucket to search in stat cache during creating new file
#2369 - Make dir size 4096 not 0
#2351 - Added option free_space_ratio to control cache size
#2325 - Fixed a bug upload boundary calculation in StreamUpload
#2298 - Abort MPU when MPU fails to avoid litter
#2261 - Use explicit ownership for memory
#2179 - Require C++11
Version 1.93 -- 19 Jul, 2023 (major changes only)
#2212 - Allow listing implicit directories
#2194 - #2209 - #2211 - #2214 - #2215 - Fix thread safety issues
#2191 - #2201 - Add support for FUSE-T on macOS
Version 1.92 -- 21 May, 2023 (major changes only)
#1802 - #2104 - New option: streamupload
#1922 - Enable noobj_cache by default
#1927 - #2101 - New option: credlib and credlib_ops
#1957 - Fixed a bug that regular files could not be created by mknod
#1964 - Added stat information to the mount point
#1970 - #1986 - Enable notsup_compat_dir by default
#2000 - #2001 - Set mtime/ctime/atime of all objects as nanosecond
#2065 - Compatible with OpenSSL 3.0
#2075 - Added proxy and proxy_cred_file option
#2135 - Changed to rename cache files when renaming large files
#2148 - New option: bucket_size
Version 1.91 -- 07 Mar, 2022 (major changes only)
#1753 - Fix RowFlush can not upload last part smaller than 5MB using NoCacheMultipartPost
#1760 - Fix IAM role retrieval from IMDSv2
#1801 - Add option to allow unsigned payloads
#1809 - Fix mixupload return EntityTooSmall while a copypart is less than 5MB after split
#1855 - Allow compilation on Windows via MSYS2
#1868 - Handle utimensat UTIME_NOW and UTIME_OMIT special values
#1871 - #1880 - Preserve sub-second precision in more situations
#1879 - Always flush open files with O_CREAT flag
#1887 - Fixed not to call Flush even if the file size is increased
#1888 - Include climits to support musl libc
Version 1.90 -- 07 Aug, 2021 (major changes only)
#1599 - Don't ignore nomultipart when storage is low
#1600 - #1602 - #1604 - #1617 - #1619 - #1620 - #1623 - #1624 - Fix POSIX compatibility issues found by pjdfstest
#1630 - Fail CheckBucket when S3 returns PermanentRedirect
#1640 - #1655 - Do not create zero-byte object when creating file
#1648 - Allow arbitrary size AWS secret keys
#1668 - #1678 - Fix race conditions
#1696 - Set explicit Content-Length: 0 when initiating MPU
#1681 - Set CURLOPT_UNRESTRICTED_AUTH when authenticating
#1723 - Add jitter to avoid thundering herd
#1728 - Loosen CheckBucket to check only the bucket
#1729 - Add support for AWS-style environment variables
Version 1.89 -- 22 Feb, 2021 (major changes only)
#1520 - #1525 - #1534 - #1549 - Propagate S3 errors to errno more accurately
#1546 - #1559 - Allow writing > 5 GB single-part objects supported by some non-AWS S3
#1553 - #1555 - Allow configuration of multipart copy size and limit to 5 GB
#1562 - Allow configuration of multipart upload threshold and reduce default to 25 MB
#1565 - Set default stat timeout to 900 seconds correctly
#1579 - #1582 - Fix data corruption while updating metadata with use_cache
Version 1.88 -- 4 Jan, 2021 (major changes only)
#1349 - Fixed a bug about move file over limit of ensure space
#1363 - #1366 - #1439 - Fix multiple race conditions
#1365 - Dynamically determine whether lseek extended options are supported
#1374 - Add support for deep archive storage class
#1385 - Plug FdEntity leaks
#1388 - Fix use_session_token option parsing
#1392 - Allow 32-bit platforms to upload single-part objects > 2 GB
#1404 - Fix dead lock in disk insufficient and optimize code
#1408 - Ensure environment variable is set when using ECS
#1413 - not call put headers if not exist pending meta
#1425 - Do not send SSE headers during bucket creation
#1432 - Add sigv4 only option
#1437 - Add atime and correct atime/mtime/ctime operations
#1447 - Fixed a bug that symlink could not be read after restarting s3fs
#1448 - #1467 - Periodically flush written data to reduce temporary local storage
#1449 - Added logfile option for non-syslog logging
#1462 - Add AWS IMDSv2 support
#1502 - #1503 - #1505 - Fix multiple issues when retrying requests
Version 1.87 -- 10 Aug, 2020 (major changes only)
#1244 - use correct content-type when complete multipart upload
#1265 - Fixed a bug of stats cache compression
#1271 - Fixed the truncation bug of stat file for cache file
#1274 - Improved strictness of cache file stats(file)
#1277 - Fixed insufficient upload size for mix multipart upload
#1282 - Warn about missing MIME types instead of exiting
#1285 - Not abort process by exception threw from s3fs_strtoofft
#1286 - Support Google Cloud Storage headers
#1295 - Added a parameter to output body to curldbg option
#1302 - Fix renames of open files with nocopyapi option
#1303 - Relink cache stats file atomically via rename
#1305 - Ignore case when comparing ETags
#1306 - Retry with exponential backoff during 500 error
#1312 - Fixed a bug about serializing from cache file
#1313 - Fixed about ParallelMixMultipartUpload
#1316 - Add support for glacier storage class
#1319 - Fixed upload error about mixuploading sparse file and truncating file
#1334 - Added SIGUSR1 option for cache file integrity test
#1341 - Change default stat_cache_expire
Version 1.86 -- 04 Feb, 2020 (major changes only)
#965 - enable various optimizations when using modern curl
#1002 - allow SSE-C keys to have NUL bytes
#1008 - add session token support
#1039 - allow large files on 32-bit systems like Raspberry Pi
#1049 - fix data corruption when external modification changes a cached object
#1063 - fix data corruption when opening a second fd to an unflushed file
#1066 - fix clock skew errors when writing large files
#1081 - allow concurrent metadata queries during data operations
#1098 - use server-side copy for partially modified files
#1107 - #1108 - fix multiple concurrency issues
#1199 - add requester_pays support
#1209 - add symlink cache
#1224 - add intelligent_ia storage tier
Version 1.85 -- 11 Mar, 2019
#804 - add Backblaze B2
#812 - Fix typo s/mutliple/multiple/
#819 - #691: Made instructions for creating password file more obvious.
#820 - Enable big writes if capable
#826 - For RPM distributions fuse-libs is enough
#831 - Add support for storage class ONEZONE_IA.
#832 - Simplify hex conversion
#833 - New installation instructions for Fedora >= 27 and CentOS7
#834 - Improve template for issues
#835 - Make the compilation instructions generic
#840 - Replace all mentions to MacOS X to macOS
#849 - Correct typo
#851 - Correctly compare list_object_max_keys
#852 - Allow credentials from ${HOME}/.aws/credentials
#853 - Replace ~ with ${HOME} in examples
#855 - Include StackOverflow in FAQs
#856 - Add icon for s3fs
#859 - Upload S3 parts without batching
#861 - Add 'profile' option to command line help.
#865 - fix multihead warning check
#866 - Multi-arch support for ppc64le
#870 - Correct typos in command-line parsing
#874 - Address cppcheck 1.86 errors
#877 - Check arguments and environment before .aws/creds
#882 - [curl] Assume long encryption keys are base64 encoded
#885 - Update s3fs_util.cpp for correspondence of Nextcloud contype
#888 - Add Server Fault to FAQs
#892 - Repair xattr tests
#893 - Store and retrieve file change time
#894 - Default uid/gid/mode when object lacks permissions
#895 - Emit more friendly error for buckets with dots
#898 - Flush file before renaming
#899 - Tighten up HTTP response code check
#900 - Plug memory leak
#901 - Plug memory leaks
#902 - Avoid pass-by-value when not necessary
#903 - Prefer find(char) over find(const char *)
#904 - Remove unnecessary calls to std::string::c_str
#905 - Fix comparison in s3fs_strtoofft
#906 - Prefer HTTPS links where possible
#908 - Added an error message when HTTP 301 status
#909 - Ignore after period character of floating point in x-amz-meta-mtime
#910 - Added a missing extension to .gitignore, and formatted dot files
#911 - Added detail error message when HTTP 301/307 status
#912 - Automatic region change made possible other than us-east-1(default)
#913 - Prefer abort over assert(false)
#914 - Issue readdir HEAD requests without batching
#917 - Reference better-known AWS CLI for compatibility
#918 - Load tail range during overwrite
#919 - Add test for mv non-empty directory
#920 - Remove unnecessary string copies
#921 - Remove redundant string initializations
#923 - Reverted automatic region change and changed messages
#924 - Prefer empty over size checks
#925 - Remove redundant null checks before delete
#926 - Accept paths with : in them
#930 - Correct enable_content_md5 docs
#931 - Correct sigv2 typo
#932 - Prefer AutoLock for synchronization
#933 - Remove mirror path when deleting cache
#934 - Checked and corrected all typo
#937 - Disable malloc_trim
#938 - Remove unneeded void parameter
#939 - Prefer specific [io]stringstream where possible
#940 - Copy parts in parallel
#942 - Ensure s3fs compiles with C++03
#943 - Return not supported when hard linking
#944 - Repair utility mode
#946 - Simplify async request completion code
#948 - Add logging for too many parts
#949 - Implement exponential backoff for 503
#950 - Added S3FS_MALLOC_TRIM build switch
#951 - Added a non-interactive option to utility mode
#952 - Automatically abort failed multipart requests
#953 - Update s3ql link
#954 - Clear containers instead of individual erases
#955 - Address miscellaneous clang-tidy warnings
#957 - Upgrade to S3Proxy 1.6.1
#958 - Document lack of inotify support
#959 - Fixed code for latest cppcheck error on OSX
#960 - Wtf8
#961 - Work around cppcheck warnings
#965 - Improvement of curl session pool for multipart
#967 - Increase FdEntity reference count when returning
#969 - Fix lazy typo
#970 - Remove from file from stat cache during rename
#972 - Add instructions for Amazon Linux
#974 - Changed the description order of man page options
#975 - Fixed ref-count when error occurred.
#977 - Make macOS instructions consistent with others
Version 1.84 -- Jul 8, 2018
#704 - Update README.md with details about .passwd-s3fs
#710 - add disk space reservation
#712 - Added Cygwin build options
#714 - reduce lock contention on file open
#724 - don't fail multirequest on single thread error
#726 - add an instance_name option for logging
#727 - Fixed Travis CI error about cppcheck - #713
#729 - FreeBSD build fixes
#733 - More useful error message for dupe entries in passwd file
#739 - cleanup curl handle state on retries
#745 - don't fail mkdir when directory exists
#753 - fix xpath selector in bucket listing
#754 - Validate the URL format for http/https
#755 - Added reset curl handle when returning to handle pool
#756 - Optimize defaults
#761 - Simplify installation for Ubuntu 16.04
#762 - Upgrade to S3Proxy 1.6.0
#763 - cleanup curl handles before curl share
#764 - Remove false multihead warnings
#765 - Add Debian installation instructions
#766 - Remove s3fs-python
#768 - Fixed memory leak
#769 - Revert "enable FUSE read_sync by default"
#774 - Option for IAM authentication endpoint
#780 - gnutls_auth: initialize libgcrypt
#781 - Fixed an error by cppcheck on OSX
#786 - Log messages for 5xx and 4xx HTTP response code
#789 - Instructions for SUSE and openSUSE prebuilt packages
#793 - Added list_object_max_keys option based on #783 PR
Version 1.83 -- Dec 17, 2017
#606 - Add Homebrew instructions
#608 - Fix chown_nocopy losing existing uid/gid if unspecified
#609 - Group permission checks sometimes fail with large number of groups
#611 - Fixed clock_gettime build failure on macOS 10.12 Sierra - #600
#621 - Upgrade to S3Proxy 1.5.3
#627 - Update README.md
#630 - Added travis test on osx for #601
#631 - Merged macosx branch into master branch #601
#636 - Fix intermittent upload failures on macOS
#637 - Add blurb about non-Amazon S3 implementations
#638 - Minor fixes to README
#639 - Update Homebrew instructions
#642 - Fixed potential atomic violation in S3fsCurl::AddUserAgent - #633
#644 - Fixed with unnecessary equal in POST uploads url argument - #643
#645 - Configure S3Proxy for SSL
#646 - Simplify S3Proxy PID handling
#652 - Fix s3fs_init message
#659 - Do not fail updating directory when removing old-style object(ref #658)
#660 - Refixed s3fs_init message(ref #652)
#663 - Lock FdEntity when mutating orgmeta
#664 - auth headers insertion refactoring
#668 - Changed .travis.yml for fixing not found gpg2 on osx
#669 - add IBM IAM authentication support
#670 - Fixed a bug in S3fsCurl::LocateBundle
#671 - Add support for ECS metadata endpoint
#675 - Reduce use of preprocessor
#676 - Move str definition from header to implementation
#677 - Add s3proxy to .gitignore
#679 - README.md Addition
#681 - Changed functions about reading passwd file
#684 - Correct signedness warning
#686 - remove use of jsoncpp
#688 - Improved use of temporary files - #678
#690 - Added option ecs description to man page
#692 - Updated template md files for issue and pr
#695 - fix condition for parallel download
#697 - Fixing race condition in FdEntity::GetStats
#699 - Fix dbglevel usage
Version 1.82 -- May 13, 2017
#597 - Not fallback to HTTP - #596
#598 - Updated ChangeLog and configure.ac for release 1.82
Version 1.81 -- May 13, 2017
#426 - Updated to correct ChangeLog
#431 - fix typo s/controll/control/
#432 - Include location constraint when creating bucket
#433 - Correct search and replace typo
#440 - Handled all curl error without exiting process - #437
#443 - Fix for leaks during stat cache entry expiry / truncation (#340)
#444 - Add mirror file logic for removing cache file
#447 - added fuse package for mounting via /etc/fstab, fixes #417
#449 - Accept mount options compatible with mtab
#451 - Correct path in README
#454 - Changed for accepting mount options compatible with mtab - #449
#466 - Fixed a bug about could not copy file mode from org file
#471 - Added use_xattr option for #467 and #460
#477 - OS-specific correspondence of the extended attribute header
#483 - Trim symbolic link original path in file
#487 - Split header debugging onto multiple lines for easier reading
#488 - Fixed searching Content-Length without case sensitive - #480
#489 - Changed headers_t map using nocase compare function - #488
#494 - Fix typo s/destroied/destroyed/
#495 - Fix invalid V4 signature on multipart copy requests
#498 - Upgrade to S3Proxy 1.5.1
#502 - Fixed issue#435 branch codes for remaining bugs(2)
#503 - Add missing call to mtime test
#504 - Use describe helper function
#505 - Correct typos
#509 - Use server-provided ETag during complete upload
#511 - Fixed a bug about uploading NULL to some part of the file contents
#512 - Changed clock_gettime func to s3fs_clock_gettime for homebrew - #468
#513 - Added issue and PR templates.
#517 - Update s3fs.1 - removed duplicated word
#520 - Added links for eventual consistency in README.md - #515
#539 - Upgrade to S3Proxy 1.5.2
#540 - Address cppcheck 1.77 warnings
#545 - Changed base cached time of stat_cache_expire option - #523
#546 - Fixed double initialization of SSL library at foreground
#550 - Add umount instruction for unprivileged user
#551 - Updated stat_cache_expire option description - #545
#552 - switch S3fsMultiCurl to use foreground threads
#553 - add TLS cipher suites customization
#554 - cleanup cache directory when running out of disk space
#555 - don't sign empty headers (as they are discarded
#556 - fix multipart upload handling without cache
#557 - Added check_cache_dir_exist option(refixed #347) - #538
#558 - Fixed a bug in logic about truncating stat cache
#560 - Fixed about multipart uploading at no free space related to #509
#567 - Do not send ACL unless overridden
#576 - Added option for complementing lack of stat mode
#578 - Refactored the get_object_attribute function
#579 - Added notsup_compat_dir option
#580 - Enhanced bucket/path parameter check
#582 - Check errors returned in 200 OK responses for put header request
#583 - Updated limit object size in s3fs man page
#585 - Fixed failure to upload/copy with SSE_C and SSE_KMS
#587 - Changed copyright year format for debian pkg
#588 - Default transport to HTTPS
#590 - Updated man page for default_acl option - #567
#593 - Backward compatible for changing default transport to HTTPS
#594 - Check bucket at public bucket and add nocopyapi option automatically
#595 - Updated ChangeLog and configure.ac for release 1.81
Version 1.80 -- May 29, 2016
#213 - Parse ETag from copy multipart correctly
#215 - Fix mem leak in openssl_auth.cpp:s3fs_sha256hexsum
@ -29,7 +386,7 @@ Version 1.80 -- May 29, 2016
#250 - s3fs can print version with short commit hash - #228
#251 - Skip xattr tests if utilities are missing
#252 - This fixes an issue with caching when the creation of a subdirectory …
#253 - Added chacking cache dir perms at starting.
#253 - Added checking cache dir perms at starting.
#256 - Add no atomic rename to limitations
#257 - Update README.md: Bugfix password file permissions errors
#258 - Update README.md to better explain mount upon boot
@ -57,7 +414,7 @@ Version 1.80 -- May 29, 2016
#306 - Fix read concurrency to work in parallel count
#307 - Fix pthread portability problem
#308 - Changed ensure free disk space as additional change for #306
#309 - Check pthread prtability in configure as additional change for #307
#309 - Check pthread portability in configure as additional change for #307
#310 - Update integration-test-main.sh as additional change for #300
#311 - Change error log to debug log in s3fs_read()
#313 - fix gitignore
@ -69,14 +426,14 @@ Version 1.80 -- May 29, 2016
#330 - Pass by const reference where possible
#331 - Address various clang warnings
#334 - Bucket host should include port and not path
#336 - update REAME.md for fstab
#336 - update README.md for fstab
#338 - Fixed a bug about IAMCRED type could not be retried.
#339 - Updated README.md for fstab example.
#341 - Fix the memory leak issue in fdcache.
#346 - Fix empty directory check against AWS S3
#348 - Integration test summary, continue on error
#350 - Changed cache out logic for stat - #340
#351 - Check cache dirctory path and attributes - #347
#351 - Check cache directory path and attributes - #347
#352 - Remove stat file cache dir if specified del_cache - #337
#354 - Supported regex type for additional header format - #343
#355 - Fixed codes about clock_gettime for osx
@ -103,6 +460,7 @@ Version 1.80 -- May 29, 2016
#420 - Skip early credential checks when iam_role=auto
#422 - Fixes for iam_role=auto
#424 - Added travis CI badge in README.md
#425 - Updated ChangeLog and configure.ac for release 1.80
Version 1.79 -- Jul 19, 2015
issue #60 - Emit user-friendly log messages on failed CheckBucket requests
@ -152,7 +510,7 @@ issue #184 - Add usage information for multipart_size
issue #185 - Correct obvious typos in usage and README
issue #190 - Add a no_check_certificate option.
issue #194 - Tilda in a file-name breaks things (EPERM)
issue #198 - Disasble integration tests for Travis
issue #198 - Disable integration tests for Travis
issue #199 - Supported extended attributes(retry)
issue #200 - fixed fallback to sigv2 for bucket create and GCS
issue #202 - Specialize {set,get}xattr for OS X
@ -187,99 +545,99 @@ issue #3 - Fixed local timezone was incorrectly being applied to IAM and Last-Mo
issue #4 - Fix compilation error on MacOSX with missing const
Version 1.74 -- Nov 24, 2013
This version is initial version on Github, same as on GoogleCodes(s3fs).
This version is initial version on GitHub, same as on GoogleCodes(s3fs).
https://github.com/s3fs-fuse/s3fs-fuse/releases/tag/v1.74
see more detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.74.tar.gz
see more detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.74.tar.gz
Version 1.73 -- Aug 23, 2013
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.73.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.73.tar.gz
Version 1.72 -- Aug 10, 2013
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.72.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.72.tar.gz
Version 1.71 -- Jun 15, 2013
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.71.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.71.tar.gz
Version 1.70 -- Jun 01, 2013
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.70.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.70.tar.gz
Version 1.69 -- May 15, 2013
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.69.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.69.tar.gz
Version 1.68 -- Apr 30, 2013
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.68.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.68.tar.gz
Version 1.67 -- Apr 13, 2013
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.67.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.67.tar.gz
Version 1.66 -- Apr 06, 2013
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.66.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.66.tar.gz
Version 1.65 -- Mar 30, 2013
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.65.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.65.tar.gz
Version 1.64 -- Mar 23, 2013
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.64.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.64.tar.gz
Version 1.63 -- Feb 24, 2013
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.63.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.63.tar.gz
Version 1.62 -- Jan 27, 2013
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.62.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.62.tar.gz
Version 1.61 -- Aug 30, 2011
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.61.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.61.tar.gz
Version 1.60 -- Aug 29, 2011
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.60.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.60.tar.gz
Version 1.59 -- Jul 28, 2011
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.59.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.59.tar.gz
Version 1.58 -- Jul 19, 2011
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.58.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.58.tar.gz
Version 1.57 -- Jul 07, 2011
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.57.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.57.tar.gz
Version 1.56 -- Jul 07, 2011
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.56.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.56.tar.gz
Version 1.55 -- Jul 02, 2011
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.55.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.55.tar.gz
Version 1.54 -- Jun 25, 2011
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.54.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.54.tar.gz
Version 1.53 -- Jun 22, 2011
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.53.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.53.tar.gz
Version 1.40 -- Feb 11, 2011
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.40.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.40.tar.gz
Version 1.33 -- Dec 30, 2010
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.33.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.33.tar.gz
Version 1.25 -- Dec 16, 2010
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.25.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.25.tar.gz
Version 1.19 -- Dec 2, 2010
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.19.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.19.tar.gz
Version 1.16 -- Nov 22, 2010
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.16.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.16.tar.gz
Version 1.10 -- Nov 6, 2010
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.10.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.10.tar.gz
Version 1.02 -- Oct 29, 2010
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.02.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.02.tar.gz
Version 1.01 -- Oct 28, 2010
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.01.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.01.tar.gz
Version 1.0 -- Oct 24, 2010
see detail on googlecodes: http://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.0.tar.gz
see detail on googlecodes: https://code.google.com/p/s3fs/downloads/detail?name=s3fs-1.0.tar.gz
------
Version 1.1 -- Mon Oct 18 2010

View File

@ -124,7 +124,7 @@ architecture at a time in the source code directory. After you have
installed the package for one architecture, use `make distclean' before
reconfiguring for another architecture.
On MacOS X 10.5 and later systems, you can create libraries and
On macOS 10.5 and later systems, you can create libraries and
executables that work on multiple system types--known as "fat" or
"universal" binaries--by specifying multiple `-arch' options to the
compiler but only a single `-arch' option to the preprocessor. Like

View File

@ -17,6 +17,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
######################################################################
SUBDIRS=src test doc
EXTRA_DIST=doc default_commit_hash
@ -28,12 +29,65 @@ dist-hook:
release : dist ../utils/release.sh
../utils/release.sh $(DIST_ARCHIVES)
.PHONY: cppcheck shellcheck
clang-tidy:
make -C src/ clang-tidy
make -C test/ clang-tidy
cppcheck:
cppcheck --quiet --error-exitcode=1 \
--inline-suppr \
--std=@CPP_VERSION@ \
--xml \
-D HAVE_ATTR_XATTR_H \
-D HAVE_SYS_EXTATTR_H \
-D HAVE_MALLOC_TRIM \
-U CURLE_PEER_FAILED_VERIFICATION \
--enable=all \
-U ENOATTR \
--enable=warning,style,information,missingInclude \
--suppress=missingIncludeSystem \
--suppress=unsignedLessThanZero \
--suppress=unusedFunction \
--suppress=variableScope \
--suppress=unmatchedSuppression \
--suppress=useStlAlgorithm \
--suppress=checkLevelNormal \
--suppress=normalCheckLevelMaxBranches \
--addon=test/map-subscript-read.py \
src/ test/
#
# ShellCheck
#
SHELLCHECK_CMD = shellcheck
SHELLCHECK_SH_OPT = --shell=sh
SHELLCHECK_BASH_OPT = --shell=bash
# [NOTE]
# To control error warnings as a whole, specify the "SC<number>" with the following variables.
#
SHELLCHECK_COMMON_IGN = --exclude=SC1091
SHELLCHECK_CUSTOM_IGN = --exclude=SC1091
shellcheck:
@if type shellcheck > /dev/null 2>&1; then \
echo "* ShellCheck version"; \
$(SHELLCHECK_CMD) --version; \
echo ""; \
echo "* Check all sh files with ShellCheck"; \
LC_ALL=C.UTF-8 $(SHELLCHECK_CMD) $(SHELLCHECK_SH_OPT) $(SHELLCHECK_COMMON_IGN) $$(grep '#![[:space:]]*/bin/sh' $$(find . -type f -name \*.sh) | sed -e 's|^\(.*\):#\!.*$$|\1|g') || exit 1; \
echo "-> No error was detected."; \
echo ""; \
echo "* Check all bash files with ShellCheck"; \
LC_ALL=C.UTF-8 $(SHELLCHECK_CMD) $(SHELLCHECK_BASH_OPT) $(SHELLCHECK_COMMON_IGN) $$(grep '#![[:space:]]*/bin/bash' $$(find . -type f -name \*.sh) | sed -e 's|^\(.*\):#\!.*$$|\1|g') || exit 1; \
echo "-> No error was detected."; \
else \
echo "* ShellCheck is not installed, so skip this."; \
fi
#
# Local variables:
# tab-width: 4
# c-basic-offset: 4
# End:
# vim600: expandtab sw=4 ts=4 fdm=marker
# vim<600: expandtab sw=4 ts=4
#

193
README.md
View File

@ -1,15 +1,19 @@
s3fs
====
# s3fs
s3fs allows Linux and Mac OS X to mount an S3 bucket via FUSE.
s3fs preserves the native object format for files, allowing use of other tools like [s3cmd](http://s3tools.org/s3cmd).
[![Build Status](https://travis-ci.org/s3fs-fuse/s3fs-fuse.svg?branch=master)](https://travis-ci.org/s3fs-fuse/s3fs-fuse)
s3fs allows Linux, macOS, and FreeBSD to mount an S3 bucket via [FUSE(Filesystem in Userspace)](https://github.com/libfuse/libfuse).
s3fs makes you operate files and directories in S3 bucket like a local file system.
s3fs preserves the native object format for files, allowing use of other tools like [AWS CLI](https://github.com/aws/aws-cli).
Features
--------
[![s3fs-fuse CI](https://github.com/s3fs-fuse/s3fs-fuse/actions/workflows/ci.yml/badge.svg)](https://github.com/s3fs-fuse/s3fs-fuse/actions/workflows/ci.yml)
[![Twitter Follow](https://img.shields.io/twitter/follow/s3fsfuse.svg?style=social&label=Follow)](https://twitter.com/s3fsfuse)
![s3fs-fuse](https://github.com/ggtakec/s3fs-fuse-images/blob/master/images/s3fslogo.png)
## Features
* large subset of POSIX including reading/writing files, directories, symlinks, mode, uid/gid, and extended attributes
* compatible with Amazon S3, Google Cloud Storage, and other S3-based object stores
* compatible with Amazon S3, and other [S3-based object stores](https://github.com/s3fs-fuse/s3fs-fuse/wiki/Non-Amazon-S3)
* allows random writes and appends
* large files via multi-part upload
* renames via server-side copy
* optional server-side encryption
@ -19,109 +23,162 @@ Features
* user-specified regions, including Amazon GovCloud
* authenticate via v2 or v4 signatures
Installation
------------
## Installation
Ensure you have all the dependencies:
Many systems provide pre-built packages:
On Ubuntu 14.04:
* Amazon Linux via EPEL:
```
sudo amazon-linux-extras install epel
sudo yum install s3fs-fuse
```
* Arch Linux:
```
sudo pacman -S s3fs-fuse
```
* Debian 9 and Ubuntu 16.04 or newer:
```
sudo apt install s3fs
```
* Fedora 27 or newer:
```
sudo dnf install s3fs-fuse
```
* Gentoo:
```
sudo emerge net-fs/s3fs
```
* RHEL and CentOS 7 or newer via EPEL:
```
sudo yum install epel-release
sudo yum install s3fs-fuse
```
* SUSE 12 and openSUSE 42.1 or newer:
```
sudo zypper install s3fs
```
* macOS 10.12 and newer via [Homebrew](https://brew.sh/):
```
brew install --cask macfuse
brew install gromgit/fuse/s3fs-mac
```
* FreeBSD:
```
pkg install fusefs-s3fs
```
* Windows:
Windows has its own install, seening in [this link](COMPILATION.md)
Otherwise consult the [compilation instructions](COMPILATION.md).
## Examples
s3fs supports the standard
[AWS credentials file](https://docs.aws.amazon.com/cli/latest/userguide/cli-config-files.html)
stored in `${HOME}/.aws/credentials`. Alternatively, s3fs supports a custom passwd file.
Finally s3fs recognizes the `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN`
environment variables.
The default location for the s3fs password file can be created:
* using a `.passwd-s3fs` file in the users home directory (i.e. `${HOME}/.passwd-s3fs`)
* using the system-wide `/etc/passwd-s3fs` file
Enter your credentials in a file `${HOME}/.passwd-s3fs` and set
owner-only permissions:
```
sudo apt-get install automake autotools-dev g++ git libcurl4-gnutls-dev libfuse-dev libssl-dev libxml2-dev make pkg-config
```
On CentOS 7:
```
sudo yum install automake fuse-devel gcc-c++ git libcurl-devel libxml2-devel make openssl-devel
```
Compile from master via the following commands:
```
git clone https://github.com/s3fs-fuse/s3fs-fuse.git
cd s3fs-fuse
./autogen.sh
./configure
make
sudo make install
```
Examples
--------
Enter your S3 identity and credential in a file `/path/to/passwd`:
```
echo MYIDENTITY:MYCREDENTIAL > /path/to/passwd
```
Make sure the file has proper permissions (if you get 'permissions' error when mounting) `/path/to/passwd`:
```
chmod 600 /path/to/passwd
echo ACCESS_KEY_ID:SECRET_ACCESS_KEY > ${HOME}/.passwd-s3fs
chmod 600 ${HOME}/.passwd-s3fs
```
Run s3fs with an existing bucket `mybucket` and directory `/path/to/mountpoint`:
```
s3fs mybucket /path/to/mountpoint -o passwd_file=/path/to/passwd
s3fs mybucket /path/to/mountpoint -o passwd_file=${HOME}/.passwd-s3fs
```
If you encounter any errors, enable debug output:
```
s3fs mybucket /path/to/mountpoint -o passwd_file=/path/to/passwd -d -d -f -o f2 -o curldbg
s3fs mybucket /path/to/mountpoint -o passwd_file=${HOME}/.passwd-s3fs -o dbglevel=info -f -o curldbg
```
You can also mount on boot by entering the following line to `/etc/fstab`:
```
s3fs#mybucket /path/to/mountpoint fuse _netdev,allow_other 0 0
or
mybucket /path/to/mountpoint fuse.s3fs _netdev,allow_other 0 0
```
If you use s3fs with a non-Amazon S3 implementation, specify the URL and path-style requests:
```
s3fs mybucket /path/to/mountpoint -o passwd_file=${HOME}/.passwd-s3fs -o url=https://url.to.s3/ -o use_path_request_style
```
or(fstab)
```
mybucket /path/to/mountpoint fuse.s3fs _netdev,allow_other,use_path_request_style,url=https://url.to.s3/ 0 0
```
Note: You may also want to create the global credential file first
```
echo MYIDENTITY:MYCREDENTIAL > /etc/passwd-s3fs
chmod 600 /path/to/passwd
echo ACCESS_KEY_ID:SECRET_ACCESS_KEY > /etc/passwd-s3fs
chmod 600 /etc/passwd-s3fs
```
Note2: You may also need to make sure `netfs` service is start on boot
Limitations
-----------
## Limitations
Generally S3 cannot offer the same performance or semantics as a local file system. More specifically:
* random writes or appends to files require rewriting the entire file
* random writes or appends to files require rewriting the entire object, optimized with multi-part upload copy
* metadata operations such as listing directories have poor performance due to network latency
* [eventual consistency](https://en.wikipedia.org/wiki/Eventual_consistency) can temporarily yield stale data
* non-AWS providers may have [eventual consistency](https://en.wikipedia.org/wiki/Eventual_consistency) so reads can temporarily yield stale data (AWS offers read-after-write consistency [since Dec 2020](https://aws.amazon.com/about-aws/whats-new/2020/12/amazon-s3-now-delivers-strong-read-after-write-consistency-automatically-for-all-applications/))
* no atomic renames of files or directories
* no coordination between multiple clients mounting the same bucket
* no hard links
* inotify detects only local modifications, not external ones by other clients or tools
References
----------
## References
* [CSI for S3](https://github.com/ctrox/csi-s3) - Kubernetes CSI driver
* [docker-s3fs-client](https://github.com/efrecon/docker-s3fs-client) - Docker image containing s3fs
* [goofys](https://github.com/kahing/goofys) - similar to s3fs but has better performance and less POSIX compatibility
* [s3backer](https://github.com/archiecobbs/s3backer) - mount an S3 bucket as a single file
* [s3fs-python](https://fedorahosted.org/s3fs/) - an older and less complete implementation written in Python
* [S3Proxy](https://github.com/andrewgaul/s3proxy) - combine with s3fs to mount EMC Atmos, Microsoft Azure, and OpenStack Swift buckets
* [s3ql](https://bitbucket.org/nikratio/s3ql/) - similar to s3fs but uses its own object format
* [S3Proxy](https://github.com/gaul/s3proxy) - combine with s3fs to mount Backblaze B2, EMC Atmos, Microsoft Azure, and OpenStack Swift buckets
* [s3ql](https://github.com/s3ql/s3ql/) - similar to s3fs but uses its own object format
* [YAS3FS](https://github.com/danilop/yas3fs) - similar to s3fs but uses SNS to allow multiple clients to mount a bucket
Frequently Asked Questions
--------------------------
* [FAQ wiki page](https://github.com/s3fs-fuse/s3fs-fuse/wiki/FAQ)
## Frequently Asked Questions
License
-------
* [FAQ wiki page](https://github.com/s3fs-fuse/s3fs-fuse/wiki/FAQ)
* [s3fs on Stack Overflow](https://stackoverflow.com/questions/tagged/s3fs)
* [s3fs on Server Fault](https://serverfault.com/questions/tagged/s3fs)
## License
Copyright (C) 2010 Randy Rizun <rrizun@gmail.com>

View File

@ -1,5 +1,5 @@
#! /bin/sh
#!/bin/sh
#
# This file is part of S3FS.
#
# Copyright 2009, 2010 Free Software Foundation, Inc.
@ -21,21 +21,24 @@
echo "--- Make commit hash file -------"
SHORTHASH="unknown"
type git > /dev/null 2>&1
if [ $? -eq 0 -a -d .git ]; then
RESULT=`git rev-parse --short HEAD`
if [ $? -eq 0 ]; then
SHORTHASH=${RESULT}
fi
SHORTHASH=""
if command -v git > /dev/null 2>&1 && test -d .git; then
if SHORTHASH=$(git rev-parse --short HEAD); then
echo " -> Git commit hash : ${SHORTHASH}"
else
echo " -> Not get git commit hash"
fi
else
echo " -> Not found git command or .git directory"
fi
echo ${SHORTHASH} > default_commit_hash
echo "${SHORTHASH}" > default_commit_hash
echo "--- Finished commit hash file ---"
echo "--- Start autotools -------------"
aclocal \
autoupdate \
&& aclocal \
&& autoheader \
&& automake --add-missing \
&& autoconf
@ -44,3 +47,11 @@ echo "--- Finished autotools ----------"
exit 0
#
# Local variables:
# tab-width: 4
# c-basic-offset: 4
# End:
# vim600: expandtab sw=4 ts=4 fdm=marker
# vim<600: expandtab sw=4 ts=4
#

View File

@ -19,25 +19,39 @@
######################################################################
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
AC_INIT(s3fs, 1.80)
AC_PREREQ([2.69])
AC_INIT([s3fs],[1.95])
AC_CONFIG_HEADER([config.h])
AC_CANONICAL_SYSTEM
AC_CANONICAL_TARGET
AM_INIT_AUTOMAKE([foreign])
AC_PROG_CXX
AC_PROG_CC
CXXFLAGS="$CXXFLAGS -Wall -D_FILE_OFFSET_BITS=64"
AC_CHECK_HEADERS([sys/xattr.h])
AC_CHECK_HEADERS([attr/xattr.h])
AC_CHECK_HEADERS([sys/extattr.h])
AC_CHECK_FUNCS([fallocate])
CPP_VERSION=c++14
AC_SUBST([CPP_VERSION])
CXXFLAGS="-Wall -fno-exceptions -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=3 -std=$CPP_VERSION $CXXFLAGS"
dnl ----------------------------------------------
dnl For OSX
dnl For macOS
dnl ----------------------------------------------
case "$target" in
*-cygwin* )
# Do something specific for windows using winfsp
CXXFLAGS="$CXXFLAGS -D_GNU_SOURCE=1"
min_fuse_version=2.8
;;
*-darwin* )
# Do something specific for mac
min_fuse_version=2.7.3
min_fuse_t_version=1.0.20
;;
*)
# Default Case
@ -46,11 +60,24 @@ case "$target" in
;;
esac
dnl ----------------------------------------------
dnl Checking the FUSE library
dnl ----------------------------------------------
dnl Distinguish between Linux (libfuse) and macOS (FUSE-T).
dnl
found_fuse_t=no
PKG_CHECK_MODULES([FUSE_T], [fuse-t >= ${min_fuse_t_version}], [found_fuse_t=yes], [found_fuse_t=no])
AS_IF([test "$found_fuse_t" = "yes"],
[PKG_CHECK_MODULES([fuse_library_checking], [fuse-t >= ${min_fuse_t_version}])],
[PKG_CHECK_MODULES([fuse_library_checking], [fuse >= ${min_fuse_version}])])
dnl ----------------------------------------------
dnl Choice SSL library
dnl ----------------------------------------------
auth_lib=na
nettle_lib=no
use_openssl_30=no
dnl
dnl nettle library
@ -170,15 +197,24 @@ AS_IF(
dnl
dnl For PKG_CONFIG before checking nss/gnutls.
dnl this is redundant checking, but we need checking before following.
dnl
PKG_CHECK_MODULES([common_lib_checking], [fuse >= ${min_fuse_version} libcurl >= 7.0 libxml-2.0 >= 2.6])
AC_MSG_CHECKING([compile s3fs with])
case "${auth_lib}" in
openssl)
AC_MSG_RESULT(OpenSSL)
PKG_CHECK_MODULES([DEPS], [fuse >= ${min_fuse_version} libcurl >= 7.0 libxml-2.0 >= 2.6 libcrypto >= 0.9])
AS_IF([test "$found_fuse_t" = "yes"],
[PKG_CHECK_MODULES([DEPS], [fuse-t >= ${min_fuse_t_version} libcurl >= 7.0 libxml-2.0 >= 2.6 libcrypto >= 0.9 ])],
[PKG_CHECK_MODULES([DEPS], [fuse >= ${min_fuse_version} libcurl >= 7.0 libxml-2.0 >= 2.6 libcrypto >= 0.9 ])])
AC_MSG_CHECKING([openssl 3.0 or later])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([[#include <openssl/opensslv.h>
#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L
#error "found openssl is 3.0 or later(so compiling is stopped with error)"
#endif]], [[]])],
[AC_MSG_RESULT(no)],
[AC_MSG_RESULT(yes); use_openssl_30=yes])
;;
gnutls)
AC_MSG_RESULT(GnuTLS-gcrypt)
@ -187,7 +223,9 @@ gnutls)
AS_IF([test "$gnutls_nettle" = ""], [AC_CHECK_LIB(gcrypt, gcry_control, [gnutls_nettle=0])])
AS_IF([test $gnutls_nettle = 0],
[
PKG_CHECK_MODULES([DEPS], [fuse >= ${min_fuse_version} libcurl >= 7.0 libxml-2.0 >= 2.6 gnutls >= 2.12.0 ])
AS_IF([test "$found_fuse_t" = "yes"],
[PKG_CHECK_MODULES([DEPS], [fuse-t >= ${min_fuse_t_version} libcurl >= 7.0 libxml-2.0 >= 2.6 gnutls >= 2.12.0 ])],
[PKG_CHECK_MODULES([DEPS], [fuse >= ${min_fuse_version} libcurl >= 7.0 libxml-2.0 >= 2.6 gnutls >= 2.12.0 ])])
LIBS="-lgnutls -lgcrypt $LIBS"
AC_MSG_CHECKING([gnutls is build with])
AC_MSG_RESULT(gcrypt)
@ -201,7 +239,9 @@ nettle)
AS_IF([test "$gnutls_nettle" = ""], [AC_CHECK_LIB(nettle, nettle_MD5Init, [gnutls_nettle=1])])
AS_IF([test $gnutls_nettle = 1],
[
PKG_CHECK_MODULES([DEPS], [fuse >= ${min_fuse_version} libcurl >= 7.0 libxml-2.0 >= 2.6 nettle >= 2.7.1 ])
AS_IF([test "$found_fuse_t" = "yes"],
[PKG_CHECK_MODULES([DEPS], [fuse-t >= ${min_fuse_t_version} libcurl >= 7.0 libxml-2.0 >= 2.6 nettle >= 2.7.1 ])],
[PKG_CHECK_MODULES([DEPS], [fuse >= ${min_fuse_version} libcurl >= 7.0 libxml-2.0 >= 2.6 nettle >= 2.7.1 ])])
LIBS="-lgnutls -lnettle $LIBS"
AC_MSG_CHECKING([gnutls is build with])
AC_MSG_RESULT(nettle)
@ -210,7 +250,9 @@ nettle)
;;
nss)
AC_MSG_RESULT(NSS)
PKG_CHECK_MODULES([DEPS], [fuse >= ${min_fuse_version} libcurl >= 7.0 libxml-2.0 >= 2.6 nss >= 3.15.0 ])
AS_IF([test "$found_fuse_t" = "yes"],
[PKG_CHECK_MODULES([DEPS], [fuse-t >= ${min_fuse_t_version} libcurl >= 7.0 libxml-2.0 >= 2.6 nss >= 3.15.0 ])],
[PKG_CHECK_MODULES([DEPS], [fuse >= ${min_fuse_version} libcurl >= 7.0 libxml-2.0 >= 2.6 nss >= 3.15.0 ])])
;;
*)
AC_MSG_ERROR([unknown ssl library type.])
@ -218,6 +260,7 @@ nss)
esac
AM_CONDITIONAL([USE_SSL_OPENSSL], [test "$auth_lib" = openssl])
AM_CONDITIONAL([USE_SSL_OPENSSL_30], [test "$use_openssl_30" = yes])
AM_CONDITIONAL([USE_SSL_GNUTLS], [test "$auth_lib" = gnutls -o "$auth_lib" = nettle])
AM_CONDITIONAL([USE_GNUTLS_NETTLE], [test "$auth_lib" = nettle])
AM_CONDITIONAL([USE_SSL_NSS], [test "$auth_lib" = nss])
@ -228,7 +271,7 @@ dnl ----------------------------------------------
dnl malloc_trim function
AC_CHECK_FUNCS([malloc_trim])
dnl clock_gettime function(osx)
dnl clock_gettime function(macos)
AC_SEARCH_LIBS([clock_gettime],[rt posix4])
AC_CHECK_FUNCS([clock_gettime])
@ -255,24 +298,94 @@ AC_COMPILE_IFELSE(
]
)
dnl ----------------------------------------------
dnl check CURLoption
dnl ----------------------------------------------
dnl CURLOPT_TCP_KEEPALIVE (is supported by 7.25.0 and later)
AC_MSG_CHECKING([checking CURLOPT_TCP_KEEPALIVE])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([[#include <curl/curl.h>]],
[[CURLoption opt = CURLOPT_TCP_KEEPALIVE;]])
],
[AC_DEFINE(HAVE_CURLOPT_TCP_KEEPALIVE, 1, [Define to 1 if libcurl has CURLOPT_TCP_KEEPALIVE CURLoption])
AC_MSG_RESULT(yes)
],
[AC_DEFINE(HAVE_CURLOPT_TCP_KEEPALIVE, 0, [Define to 1 if libcurl has CURLOPT_TCP_KEEPALIVE CURLoption])
AC_MSG_RESULT(no)
]
)
dnl CURLOPT_SSL_ENABLE_ALPN (is supported by 7.36.0 and later)
AC_MSG_CHECKING([checking CURLOPT_SSL_ENABLE_ALPN])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([[#include <curl/curl.h>]],
[[CURLoption opt = CURLOPT_SSL_ENABLE_ALPN;]])
],
[AC_DEFINE(HAVE_CURLOPT_SSL_ENABLE_ALPN, 1, [Define to 1 if libcurl has CURLOPT_SSL_ENABLE_ALPN CURLoption])
AC_MSG_RESULT(yes)
],
[AC_DEFINE(HAVE_CURLOPT_SSL_ENABLE_ALPN, 0, [Define to 1 if libcurl has CURLOPT_SSL_ENABLE_ALPN CURLoption])
AC_MSG_RESULT(no)
]
)
dnl CURLOPT_KEEP_SENDING_ON_ERROR (is supported by 7.51.0 and later)
AC_MSG_CHECKING([checking CURLOPT_KEEP_SENDING_ON_ERROR])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([[#include <curl/curl.h>]],
[[CURLoption opt = CURLOPT_KEEP_SENDING_ON_ERROR;]])
],
[AC_DEFINE(HAVE_CURLOPT_KEEP_SENDING_ON_ERROR, 1, [Define to 1 if libcurl has CURLOPT_KEEP_SENDING_ON_ERROR CURLoption])
AC_MSG_RESULT(yes)
],
[AC_DEFINE(HAVE_CURLOPT_KEEP_SENDING_ON_ERROR, 0, [Define to 1 if libcurl has CURLOPT_KEEP_SENDING_ON_ERROR CURLoption])
AC_MSG_RESULT(no)
]
)
dnl ----------------------------------------------
dnl dl library
dnl ----------------------------------------------
AC_CHECK_LIB([dl], [dlopen, dlclose, dlerror, dlsym], [], [AC_MSG_ERROR([Could not found dlopen, dlclose, dlerror and dlsym])])
dnl ----------------------------------------------
dnl build date
dnl ----------------------------------------------
AC_SUBST([MAN_PAGE_DATE], [$(date -r doc/man/s3fs.1.in +"%B %Y")])
dnl ----------------------------------------------
dnl output files
dnl ----------------------------------------------
AC_CONFIG_FILES(Makefile src/Makefile test/Makefile doc/Makefile)
AC_CONFIG_FILES(Makefile
src/Makefile
test/Makefile
doc/Makefile
doc/man/s3fs.1)
dnl ----------------------------------------------
dnl short commit hash
dnl ----------------------------------------------
AC_CHECK_PROG([GITCMD], [git version], [yes], [no])
AC_CHECK_FILE([.git], [DOTGITDIR=yes], [DOTGITDIR=no])
AC_CHECK_PROG([GITCMD], [git --version], [yes], [no])
AS_IF([test -d .git], [DOTGITDIR=yes], [DOTGITDIR=no])
AC_MSG_CHECKING([github short commit hash])
if test x${GITCMD} = xyes -a x${DOTGITDIR} = xyes; then
GITCOMMITHASH=`git rev-parse --short HEAD`
if test "x${GITCMD}" = "xyes" -a "x${DOTGITDIR}" = "xyes"; then
TMP_GITCOMMITHASH=`git rev-parse --short HEAD`
UNTRACKED_FILES=`git status -s --untracked-files=no`
if test -n "${UNTRACKED_FILES}"; then
GITCOMMITHASH="(commit:${TMP_GITCOMMITHASH} +untracked files)"
else
GITCOMMITHASH="(commit:${TMP_GITCOMMITHASH})"
fi
elif test -f default_commit_hash; then
GITCOMMITHASH=`cat default_commit_hash`
TMP_GITCOMMITHASH=`cat default_commit_hash`
if test -n "${TMP_GITCOMMITHASH}"; then
GITCOMMITHASH="(base commit:${TMP_GITCOMMITHASH})"
else
GITCOMMITHASH=""
fi
else
GITCOMMITHASH="unknown"
GITCOMMITHASH=""
fi
AC_MSG_RESULT([${GITCOMMITHASH}])
@ -287,3 +400,11 @@ dnl ----------------------------------------------
dnl end configuration
dnl ----------------------------------------------
#
# Local variables:
# tab-width: 4
# c-basic-offset: 4
# End:
# vim600: expandtab sw=4 ts=4 fdm=marker
# vim<600: expandtab sw=4 ts=4
#

View File

@ -1,249 +0,0 @@
.TH S3FS "1" "February 2011" "S3FS" "User Commands"
.SH NAME
S3FS \- FUSE-based file system backed by Amazon S3
.SH SYNOPSIS
.SS mounting
.TP
\fBs3fs bucket[:/path] mountpoint \fP [options]
.SS unmounting
.TP
\fBumount mountpoint
.SS utility mode ( remove interrupted multipart uploading objects )
.TP
\fBs3fs \-u bucket
.SH DESCRIPTION
s3fs is a FUSE filesystem that allows you to mount an Amazon S3 bucket as a local filesystem. It stores files natively and transparently in S3 (i.e., you can use other programs to access the same files).
.SH AUTHENTICATION
The s3fs password file has this format (use this format if you have only one set of credentials):
.RS 4
\fBaccessKeyId\fP:\fBsecretAccessKey\fP
.RE
If you have more than one set of credentials, this syntax is also recognized:
.RS 4
\fBbucketName\fP:\fBaccessKeyId\fP:\fBsecretAccessKey\fP
.RE
.PP
Password files can be stored in two locations:
.RS 4
\fB/etc/passwd-s3fs\fP [0640]
\fB$HOME/.passwd-s3fs\fP [0600]
.RE
.SH OPTIONS
.SS "general options"
.TP
\fB\-h\fR \fB\-\-help\fR
print help
.TP
\fB\ \fR \fB\-\-version\fR
print version
.TP
\fB\-f\fR
FUSE foreground option - do not run as daemon.
.TP
\fB\-s\fR
FUSE singlethreaded option (disables multi-threaded operation)
.SS "mount options"
.TP
All s3fs options must given in the form where "opt" is:
<option_name>=<option_value>
.TP
\fB\-o\fR default_acl (default="private")
the default canned acl to apply to all written S3 objects, e.g., "public-read".
Any created files will have this canned acl.
Any updated files will also have this canned acl applied!
.TP
\fB\-o\fR retries (default="2")
number of times to retry a failed S3 transaction.
.TP
\fB\-o\fR use_cache (default="" which means disabled)
local folder to use for local file cache.
.TP
\fB\-o\fR del_cache - delete local file cache
delete local file cache when s3fs starts and exits.
.TP
\fB\-o\fR storage_class (default is standard)
store object with specified storage class.
this option replaces the old option use_rrs.
Possible values: standard, standard_ia, and reduced_redundancy.
.TP
\fB\-o\fR use_rrs (default is disable)
use Amazon's Reduced Redundancy Storage.
this option can not be specified with use_sse.
(can specify use_rrs=1 for old version)
this option has been replaced by new storage_class option.
.TP
\fB\-o\fR use_sse (default is disable)
Specify three type Amazon's Server-Site Encryption: SSE-S3, SSE-C or SSE-KMS. SSE-S3 uses Amazon S3-managed encryption keys, SSE-C uses customer-provided encryption keys, and SSE-KMS uses the master key which you manage in AWS KMS.
You can specify "use_sse" or "use_sse=1" enables SSE-S3 type (use_sse=1 is old type parameter).
Case of setting SSE-C, you can specify "use_sse=custom", "use_sse=custom:<custom key file path>" or "use_sse=<custom key file path>"(only <custom key file path> specified is old type parameter).
You can use "c" for short "custom".
The custom key file must be 600 permission. The file can have some lines, each line is one SSE-C key.
The first line in file is used as Customer-Provided Encryption Keys for uploading and changing headers etc.
If there are some keys after first line, those are used downloading object which are encrypted by not first key.
So that, you can keep all SSE-C keys in file, that is SSE-C key history.
If you specify "custom"("c") without file path, you need to set custom key by load_sse_c option or AWSSSECKEYS environment.(AWSSSECKEYS environment has some SSE-C keys with ":" separator.)
This option is used to decide the SSE type.
So that if you do not want to encrypt a object at uploading, but you need to decrypt encrypted object at downloaing, you can use load_sse_c option instead of this option.
For setting SSE-KMS, specify "use_sse=kmsid" or "use_sse=kmsid:<kms id>".
You can use "k" for short "kmsid".
If you san specify SSE-KMS type with your <kms id> in AWS KMS, you can set it after "kmsid:"(or "k:").
If you specify only "kmsid"("k"), you need to set AWSSSEKMSID environment which value is <kms id>.
You must be careful about that you can not use the KMS id which is not same EC2 region.
.TP
\fB\-o\fR load_sse_c - specify SSE-C keys
Specify the custom-provided encryption keys file path for decrypting at downloading.
If you use the custom-provided encryption key at uploading, you specify with "use_sse=custom".
The file has many lines, one line means one custom key.
So that you can keep all SSE-C keys in file, that is SSE-C key history.
AWSSSECKEYS environment is as same as this file contents.
.TP
\fB\-o\fR passwd_file (default="")
specify the path to the password file, which which takes precedence over the password in $HOME/.passwd-s3fs and /etc/passwd-s3fs
.TP
\fB\-o\fR ahbe_conf (default="" which means disabled)
This option specifies the configuration file path which file is the additional HTTP header by file(object) extension.
The configuration file format is below:
-----------
line = [file suffix or regex] HTTP-header [HTTP-values]
file suffix = file(object) suffix, if this field is empty, it means "reg:(.*)".(=all object).
regex = regular expression to match the file(object) path. this type starts with "reg:" prefix.
HTTP-header = additional HTTP header name
HTTP-values = additional HTTP header value
-----------
Sample:
-----------
.gz Content-Encoding gzip
.Z Content-Encoding compress
reg:^/MYDIR/(.*)[.]t2$ Content-Encoding text2
-----------
A sample configuration file is uploaded in "test" directory.
If you specify this option for set "Content-Encoding" HTTP header, please take care for RFC 2616.
.TP
\fB\-o\fR public_bucket (default="" which means disabled)
anonymously mount a public bucket when set to 1, ignores the $HOME/.passwd-s3fs and /etc/passwd-s3fs files.
.TP
\fB\-o\fR connect_timeout (default="300" seconds)
time to wait for connection before giving up.
.TP
\fB\-o\fR readwrite_timeout (default="60" seconds)
time to wait between read/write activity before giving up.
.TP
\fB\-o\fR max_stat_cache_size (default="1000" entries (about 4MB))
maximum number of entries in the stat cache
.TP
\fB\-o\fR stat_cache_expire (default is no expire)
specify expire time(seconds) for entries in the stat cache
.TP
\fB\-o\fR enable_noobj_cache (default is disable)
enable cache entries for the object which does not exist.
s3fs always has to check whether file(or sub directory) exists under object(path) when s3fs does some command, since s3fs has recognized a directory which does not exist and has files or sub directories under itself.
It increases ListBucket request and makes performance bad.
You can specify this option for performance, s3fs memorizes in stat cache that the object(file or directory) does not exist.
.TP
\fB\-o\fR no_check_certificate (by default this option is disabled)
do not check ssl certificate.
server certificate won't be checked against the available certificate authorities.
.TP
\fB\-o\fR nodnscache - disable dns cache.
s3fs is always using dns cache, this option make dns cache disable.
.TP
\fB\-o\fR nosscache - disable ssl session cache.
s3fs is always using ssl session cache, this option make ssl session cache disable.
.TP
\fB\-o\fR multireq_max (default="20")
maximum number of parallel request for listing objects.
.TP
\fB\-o\fR parallel_count (default="5")
number of parallel request for uploading big objects.
s3fs uploads large object(default:over 20MB) by multipart post request, and sends parallel requests.
This option limits parallel request count which s3fs requests at once.
It is necessary to set this value depending on a CPU and a network band.
.TP
\fB\-o\fR multipart_size(default="10"(10MB))
number of one part size in multipart uploading request.
The default size is 10MB(10485760byte), minimum value is 5MB(5242880byte).
Specify number of MB and over 5(MB).
.TP
\fB\-o\fR ensure_diskfree(default the same as multipart_size value)
sets MB to ensure disk free space. This option means the threshold of free space size on disk which is used for the cache file by s3fs.
s3fs makes file for downloading, and uploading and caching files.
If the disk free space is smaller than this value, s3fs do not use diskspace as possible in exchange for the performance.
.TP
\fB\-o\fR url (default="http://s3.amazonaws.com")
sets the url to use to access Amazon S3. If you want to use HTTPS, then you can set url=https://s3.amazonaws.com
.TP
\fB\-o\fR endpoint (default="us-east-1")
sets the endpoint to use.
If this option is not specified, s3fs uses "us-east-1" region as the default.
If the s3fs could not connect to the region specified by this option, s3fs could not run.
But if you do not specify this option, and if you can not connect with the default region, s3fs will retry to automatically connect to the other region.
So s3fs can know the correct region name, because s3fs can find it in an error from the S3 server.
.TP
\fB\-o\fR sigv2 (default is signature version 4)
sets signing AWS requests by sing Signature Version 2.
.TP
\fB\-o\fR mp_umask (default is "0000")
sets umask for the mount point directory.
If allow_other option is not set, s3fs allows access to the mount point only to the owner.
In the opposite case s3fs allows access to all users as the default.
But if you set the allow_other with this option, you can controll the permission permissions of the mount point by this option like umask.
.TP
\fB\-o\fR nomultipart - disable multipart uploads
.TP
\fB\-o\fR enable_content_md5 ( default is disable )
verifying uploaded data without multipart by content-md5 header.
Enable to send "Content-MD5" header when uploading a object without multipart posting.
If this option is enabled, it has some influences on a performance of s3fs when uploading small object.
Because s3fs always checks MD5 when uploading large object, this option does not affect on large object.
.TP
\fB\-o\fR iam_role ( default is no IAM role )
This option requires the IAM role name or "auto". If you specify "auto", s3fs will automatically use the IAM role names that are set to an instance. If you specify this option without any argument, it is the same as that you have specified the "auto".
.TP
\fB\-o\fR noxmlns - disable registing xml name space.
disable registing xml name space for response of ListBucketResult and ListVersionsResult etc. Default name space is looked up from "http://s3.amazonaws.com/doc/2006-03-01".
This option should not be specified now, because s3fs looks up xmlns automatically after v1.66.
.TP
\fB\-o\fR nocopyapi - for other incomplete compatibility object storage.
For a distributed object storage which is compatibility S3 API without PUT(copy api).
If you set this option, s3fs do not use PUT with "x-amz-copy-source"(copy api). Because traffic is increased 2-3 times by this option, we do not recommend this.
.TP
\fB\-o\fR norenameapi - for other incomplete compatibility object storage.
For a distributed object storage which is compatibility S3 API without PUT(copy api).
This option is a subset of nocopyapi option. The nocopyapi option does not use copy-api for all command(ex. chmod, chown, touch, mv, etc), but this option does not use copy-api for only rename command(ex. mv).
If this option is specified with nocopapi, the s3fs ignores it.
.TP
\fB\-o\fR use_path_request_style (use legacy API calling style)
Enble compatibility with S3-like APIs which do not support the virtual-host request style, by using the older path request style.
.TP
\fB\-o\fR noua (suppress User-Agent header)
Usually s3fs outputs of the User-Agent in "s3fs/<version> (commit hash <hash>; <using ssl library name>)" format.
If this option is specified, s3fs suppresses the output of the User-Agent.
.TP
\fB\-o\fR dbglevel (default="crit")
Set the debug message level. set value as crit(critical), err(error), warn(warning), info(information) to debug level. default debug level is critical.
If s3fs run with "-d" option, the debug level is set information.
When s3fs catch the signal SIGUSR2, the debug level is bumpup.
.TP
\fB\-o\fR curldbg - put curl debug message
Put the debug message from libcurl when this option is specified.
.SH FUSE/MOUNT OPTIONS
.TP
Most of the generic mount options described in 'man mount' are supported (ro, rw, suid, nosuid, dev, nodev, exec, noexec, atime, noatime, sync async, dirsync). Filesystems are mounted with '\-onodev,nosuid' by default, which can only be overridden by a privileged user.
.TP
There are many FUSE specific mount options that can be specified. e.g. allow_other. See the FUSE README for the full set.
.SH NOTES
.TP
Maximum file size=64GB (limited by s3fs, not Amazon).
.TP
If enabled via the "use_cache" option, s3fs automatically maintains a local cache of files in the folder specified by use_cache. Whenever s3fs needs to read or write a file on S3, it first downloads the entire file locally to the folder specified by use_cache and operates on it. When fuse_release() is called, s3fs will re-upload the file to S3 if it has been changed. s3fs uses md5 checksums to minimize downloads from S3.
.TP
The folder specified by use_cache is just a local cache. It can be deleted at any time. s3fs rebuilds it on demand.
.TP
Local file caching works by calculating and comparing md5 checksums (ETag HTTP header).
.TP
s3fs leverages /etc/mime.types to "guess" the "correct" content-type based on file name extension. This means that you can copy a website to S3 and serve it up directly from S3 with correct content-types!
.SH BUGS
Due to S3's "eventual consistency" limitations, file creation can and will occasionally fail. Even after a successful create, subsequent reads can fail for an indeterminate time, even after one or more successful reads. Create and read enough files and you will eventually encounter this failure. This is not a flaw in s3fs and it is not something a FUSE wrapper like s3fs can work around. The retries option does not address this issue. Your application must either tolerate or compensate for these failures, for example by retrying creates or reads.
.SH AUTHOR
s3fs has been written by Randy Rizun <rrizun@gmail.com>.

554
doc/man/s3fs.1.in Normal file
View File

@ -0,0 +1,554 @@
.TH S3FS "1" "@MAN_PAGE_DATE@" "S3FS" "User Commands"
.SH NAME
S3FS \- FUSE-based file system backed by Amazon S3
.SH SYNOPSIS
.SS mounting
.TP
\fBs3fs bucket[:/path] mountpoint \fP [options]
.TP
\fBs3fs mountpoint \fP [options (must specify bucket= option)]
.SS unmounting
.TP
\fBumount mountpoint
For root.
.TP
\fBfusermount -u mountpoint
For unprivileged user.
.SS utility mode (remove interrupted multipart uploading objects)
.TP
\fBs3fs --incomplete-mpu-list (-u) bucket
.TP
\fBs3fs --incomplete-mpu-abort[=all | =<expire date format>] bucket
.SH DESCRIPTION
s3fs is a FUSE filesystem that allows you to mount an Amazon S3 bucket as a local filesystem. It stores files natively and transparently in S3 (i.e., you can use other programs to access the same files).
.SH AUTHENTICATION
s3fs supports the standard AWS credentials file (https://docs.aws.amazon.com/cli/latest/userguide/cli-config-files.html) stored in `${HOME}/.aws/credentials`.
Alternatively, s3fs supports a custom passwd file. Only AWS credentials file format can be used when AWS session token is required.
The s3fs password file has this format (use this format if you have only one set of credentials):
.RS 4
\fBaccessKeyId\fP:\fBsecretAccessKey\fP
.RE
If you have more than one set of credentials, this syntax is also recognized:
.RS 4
\fBbucketName\fP:\fBaccessKeyId\fP:\fBsecretAccessKey\fP
.RE
.PP
Password files can be stored in two locations:
.RS 4
\fB/etc/passwd-s3fs\fP [0640]
\fB$HOME/.passwd-s3fs\fP [0600]
.RE
.PP
s3fs also recognizes the \fBAWS_ACCESS_KEY_ID\fP and \fBAWS_SECRET_ACCESS_KEY\fP environment variables.
.SH OPTIONS
.SS "general options"
.TP
\fB\-h\fR \fB\-\-help\fR
print help
.TP
\fB\ \fR \fB\-\-version\fR
print version
.TP
\fB\-f\fR
FUSE foreground option - do not run as daemon.
.TP
\fB\-s\fR
FUSE single-threaded option (disables multi-threaded operation)
.SS "mount options"
.TP
All s3fs options must given in the form where "opt" is:
<option_name>=<option_value>
.TP
\fB\-o\fR bucket
if it is not specified bucket name (and path) in command line, must specify this option after \-o option for bucket name.
.TP
\fB\-o\fR default_acl (default="private")
the default canned acl to apply to all written s3 objects, e.g., "private", "public-read".
see https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl for the full list of canned ACLs.
.TP
\fB\-o\fR retries (default="5")
number of times to retry a failed S3 transaction.
.TP
\fB\-o\fR tmpdir (default="/tmp")
local folder for temporary files.
.TP
\fB\-o\fR use_cache (default="" which means disabled)
local folder to use for local file cache.
.TP
\fB\-o\fR check_cache_dir_exist (default is disable)
If use_cache is set, check if the cache directory exists.
If this option is not specified, it will be created at runtime when the cache directory does not exist.
.TP
\fB\-o\fR del_cache - delete local file cache
delete local file cache when s3fs starts and exits.
.TP
\fB\-o\fR storage_class (default="standard")
store object with specified storage class.
Possible values: standard, standard_ia, onezone_ia, reduced_redundancy, intelligent_tiering, glacier, glacier_ir, and deep_archive.
.TP
\fB\-o\fR use_rrs (default is disable)
use Amazon's Reduced Redundancy Storage.
this option can not be specified with use_sse.
(can specify use_rrs=1 for old version)
this option has been replaced by new storage_class option.
.TP
\fB\-o\fR use_sse (default is disable)
Specify three type Amazon's Server-Site Encryption: SSE-S3, SSE-C or SSE-KMS. SSE-S3 uses Amazon S3-managed encryption keys, SSE-C uses customer-provided encryption keys, and SSE-KMS uses the master key which you manage in AWS KMS.
You can specify "use_sse" or "use_sse=1" enables SSE-S3 type (use_sse=1 is old type parameter).
Case of setting SSE-C, you can specify "use_sse=custom", "use_sse=custom:<custom key file path>" or "use_sse=<custom key file path>" (only <custom key file path> specified is old type parameter).
You can use "c" for short "custom".
The custom key file must be 600 permission. The file can have some lines, each line is one SSE-C key.
The first line in file is used as Customer-Provided Encryption Keys for uploading and changing headers etc.
If there are some keys after first line, those are used downloading object which are encrypted by not first key.
So that, you can keep all SSE-C keys in file, that is SSE-C key history.
If you specify "custom" ("c") without file path, you need to set custom key by load_sse_c option or AWSSSECKEYS environment. (AWSSSECKEYS environment has some SSE-C keys with ":" separator.)
This option is used to decide the SSE type.
So that if you do not want to encrypt a object at uploading, but you need to decrypt encrypted object at downloading, you can use load_sse_c option instead of this option.
For setting SSE-KMS, specify "use_sse=kmsid" or "use_sse=kmsid:<kms id>".
You can use "k" for short "kmsid".
If you san specify SSE-KMS type with your <kms id> in AWS KMS, you can set it after "kmsid:" (or "k:").
If you specify only "kmsid" ("k"), you need to set AWSSSEKMSID environment which value is <kms id>.
You must be careful about that you can not use the KMS id which is not same EC2 region.
Additionally, if you specify SSE-KMS, your endpoints must use Secure Sockets Layer(SSL) or Transport Layer Security(TLS).
.TP
\fB\-o\fR load_sse_c - specify SSE-C keys
Specify the custom-provided encryption keys file path for decrypting at downloading.
If you use the custom-provided encryption key at uploading, you specify with "use_sse=custom".
The file has many lines, one line means one custom key.
So that you can keep all SSE-C keys in file, that is SSE-C key history.
AWSSSECKEYS environment is as same as this file contents.
.TP
\fB\-o\fR passwd_file (default="")
specify the path to the password file, which which takes precedence over the password in $HOME/.passwd-s3fs and /etc/passwd-s3fs
.TP
\fB\-o\fR ahbe_conf (default="" which means disabled)
This option specifies the configuration file path which file is the additional HTTP header by file (object) extension.
The configuration file format is below:
-----------
line = [file suffix or regex] HTTP-header [HTTP-values]
file suffix = file (object) suffix, if this field is empty, it means "reg:(.*)".(=all object).
regex = regular expression to match the file (object) path. this type starts with "reg:" prefix.
HTTP-header = additional HTTP header name
HTTP-values = additional HTTP header value
-----------
Sample:
-----------
.gz Content-Encoding gzip
.Z Content-Encoding compress
reg:^/MYDIR/(.*)[.]t2$ Content-Encoding text2
-----------
A sample configuration file is uploaded in "test" directory.
If you specify this option for set "Content-Encoding" HTTP header, please take care for RFC 2616.
.TP
\fB\-o\fR profile (default="default")
Choose a profile from ${HOME}/.aws/credentials to authenticate against S3.
Note that this format matches the AWS CLI format and differs from the s3fs passwd format.
.TP
\fB\-o\fR public_bucket (default="" which means disabled)
anonymously mount a public bucket when set to 1, ignores the $HOME/.passwd-s3fs and /etc/passwd-s3fs files.
S3 does not allow copy object api for anonymous users, then s3fs sets nocopyapi option automatically when public_bucket=1 option is specified.
.TP
\fB\-o\fR connect_timeout (default="300" seconds)
time to wait for connection before giving up.
.TP
\fB\-o\fR readwrite_timeout (default="120" seconds)
time to wait between read/write activity before giving up.
.TP
\fB\-o\fR list_object_max_keys (default="1000")
specify the maximum number of keys returned by S3 list object API. The default is 1000. you can set this value to 1000 or more.
.TP
\fB\-o\fR max_stat_cache_size (default="100,000" entries (about 40MB))
maximum number of entries in the stat cache and symbolic link cache.
.TP
\fB\-o\fR stat_cache_expire (default is 900)
specify expire time (seconds) for entries in the stat cache and symbolic link cache. This expire time indicates the time since cached.
.TP
\fB\-o\fR stat_cache_interval_expire (default is 900)
specify expire time (seconds) for entries in the stat cache and symbolic link cache. This expire time is based on the time from the last access time of those cache.
This option is exclusive with stat_cache_expire, and is left for compatibility with older versions.
.TP
\fB\-o\fR enable_negative_cache (default is enabled negative cache)
This option will keep non-existence of objects in a stat cache.
When this negative cache is enabled, it will not process extra HeadObject requests to search for non-existent objects, improving performance.
This feature is enabled by default, so there is no need to specify it.
.TP
\fB\-o\fR disable_negative_cache (default is enabled negative cache)
By default, s3fs keeps non-existent objects in the stat cache.
This option disables this negative caching.
This prevents delays in updates due to cache retention.
However, it may increase the number of HeadObject requests to check if an object exists, which may decrease performance.
.TP
\fB\-o\fR no_check_certificate (by default this option is disabled)
server certificate won't be checked against the available certificate authorities.
.TP
\fB\-o\fR ssl_verify_hostname (default="2")
When 0, do not verify the SSL certificate against the hostname.
.TP
\fB\-o\fR ssl_client_cert (default="")
Specify an SSL client certificate.
Specify this optional parameter in the following format:
"<SSL Cert>[:<Cert Type>[:<Private Key>[:<Key Type>
[:<Password>]]]]"
<SSL Cert>: Client certificate.
Specify the file path or NickName(for NSS, etc.).
<Cert Type>: Type of certificate, default is "PEM"(optional).
<Private Key>: Certificate's private key file(optional).
<Key Type>: Type of private key, default is "PEM"(optional).
<Password>: Passphrase of the private key(optional). It is also possible to omit this value and specify it using the environment variable "S3FS_SSL_PRIVKEY_PASSWORD".
.TP
\fB\-o\fR nodnscache - disable DNS cache.
s3fs is always using DNS cache, this option make DNS cache disable.
.TP
\fB\-o\fR nosscache - disable SSL session cache.
s3fs is always using SSL session cache, this option make SSL session cache disable.
.TP
\fB\-o\fR multipart_size (default="10")
part size, in MB, for each multipart request.
The minimum value is 5 MB and the maximum value is 5 GB.
.TP
\fB\-o\fR multipart_copy_size (default="512")
part size, in MB, for each multipart copy request, used for
renames and mixupload.
The minimum value is 5 MB and the maximum value is 5 GB.
Must be at least 512 MB to copy the maximum 5 TB object size
but lower values may improve performance.
.TP
\fB\-o\fR max_dirty_data (default="5120")
Flush dirty data to S3 after a certain number of MB written.
The minimum value is 50 MB. -1 value means disable.
Cannot be used with nomixupload.
.TP
\fB\-o\fR bucket_size (default=maximum long unsigned integer value)
The size of the bucket with which the corresponding
elements of the statvfs structure will be filled. The option
argument is an integer optionally followed by a
multiplicative suffix (GB, GiB, TB, TiB, PB, PiB,
EB, EiB) (no spaces in between). If no suffix is supplied,
bytes are assumed; eg: 20000000, 30GB, 45TiB. Note that
s3fs does not compute the actual volume size (too
expensive): by default it will assume the maximum possible
size; however, since this may confuse other software which
uses s3fs, the advertised bucket size can be set with this
option.
.TP
\fB\-o\fR ensure_diskfree (default 0)
sets MB to ensure disk free space. This option means the threshold of free space size on disk which is used for the cache file by s3fs.
s3fs makes file for downloading, uploading and caching files.
If the disk free space is smaller than this value, s3fs do not use disk space as possible in exchange for the performance.
.TP
\fB\-o\fR free_space_ratio (default="10")
sets min free space ratio of the disk. The value of this option can be between 0 and 100. It will control
the size of the cache according to this ratio to ensure that the idle ratio of the disk is greater than this value.
For example, when the disk space is 50GB, the default value will
ensure that the disk will reserve at least 50GB * 10%% = 5GB of remaining space.
.TP
\fB\-o\fR multipart_threshold (default="25")
threshold, in MB, to use multipart upload instead of
single-part. Must be at least 5 MB.
.TP
\fB\-o\fR singlepart_copy_limit (default="512")
maximum size, in MB, of a single-part copy before trying
multipart copy.
.TP
\fB\-o\fR host (default="https://s3.amazonaws.com")
Set a non-Amazon host, e.g., https://example.com.
.TP
\fB\-o\fR servicepath (default="/")
Set a service path when the non-Amazon host requires a prefix.
.TP
\fB\-o\fR url (default="https://s3.amazonaws.com")
sets the url to use to access Amazon S3. If you want to use HTTP, then you can set "url=http://s3.amazonaws.com".
If you do not use https, please specify the URL with the url option.
.TP
\fB\-o\fR region (default="us-east-1")
sets the region to use on signature version 4.
If this option is not specified, s3fs uses "us-east-1" region as the default.
If the s3fs could not connect to the region specified by this option, s3fs could not run.
But if you do not specify this option, and if you can not connect with the default region, s3fs will retry to automatically connect to the other region.
So s3fs can know the correct region name, because s3fs can find it in an error from the S3 server.
You can also specify the legacy -o endpoint which means the same thing.
.TP
\fB\-o\fR sigv2 (default is signature version 4 falling back to version 2)
sets signing AWS requests by using only signature version 2.
.TP
\fB\-o\fR sigv4 (default is signature version 4 falling back to version 2)
sets signing AWS requests by using only signature version 4.
.TP
\fB\-o\fR mp_umask (default is "0000")
sets umask for the mount point directory.
If allow_other option is not set, s3fs allows access to the mount point only to the owner.
In the opposite case s3fs allows access to all users as the default.
But if you set the allow_other with this option, you can control the permissions of the mount point by this option like umask.
.TP
\fB\-o\fR umask (default is "0000")
sets umask for files under the mountpoint. This can allow
users other than the mounting user to read and write to files
that they did not create.
.TP
\fB\-o\fR nomultipart - disable multipart uploads
.TP
\fB\-o\fR streamupload (default is disable)
Enable stream upload.
If this option is enabled, a sequential upload will be performed in parallel with the write from the part that has been written during a multipart upload.
This is expected to give better performance than other upload functions.
Note that this option is still experimental and may change in the future.
.TP
\fB\-o\fR max_thread_count (default is "10")
This value is the maximum number of parallel requests to be sent, and the number of parallel processes for head requests, multipart uploads and stream uploads.
Worker threads will be started to process requests according to this value.
.TP
\fB\-o\fR enable_content_md5 (default is disable)
Allow S3 server to check data integrity of uploads via the Content-MD5 header.
This can add CPU overhead to transfers.
.TP
\fB\-o\fR enable_unsigned_payload (default is disable)
Do not calculate Content-SHA256 for PutObject and UploadPart
payloads. This can reduce CPU overhead to transfers.
.TP
\fB\-o\fR ecs (default is disable)
This option instructs s3fs to query the ECS container credential metadata address instead of the instance metadata address.
.TP
\fB\-o\fR iam_role (default is no IAM role)
This option requires the IAM role name or "auto". If you specify "auto", s3fs will automatically use the IAM role names that are set to an instance. If you specify this option without any argument, it is the same as that you have specified the "auto".
.TP
\fB\-o\fR imdsv1only (default is to use IMDSv2 with fallback to v1)
AWS instance metadata service, used with IAM role authentication,
supports the use of an API token. If you're using an IAM role in an
environment that does not support IMDSv2, setting this flag will skip
retrieval and usage of the API token when retrieving IAM credentials.
.TP
\fB\-o\fR ibm_iam_auth (default is not using IBM IAM authentication)
This option instructs s3fs to use IBM IAM authentication. In this mode, the AWSAccessKey and AWSSecretKey will be used as IBM's Service-Instance-ID and APIKey, respectively.
.TP
\fB\-o\fR ibm_iam_endpoint (default is https://iam.cloud.ibm.com)
Sets the URL to use for IBM IAM authentication.
.TP
\fB\-o\fR credlib (default=\"\" which means disabled)
Specifies the shared library that handles the credentials containing the authentication token.
If this option is specified, the specified credential and token processing provided by the shared library ant will be performed instead of the built-in credential processing.
This option cannot be specified with passwd_file, profile, use_session_token, ecs, ibm_iam_auth, ibm_iam_endpoint, imdsv1only and iam_role option.
.TP
\fB\-o\fR credlib_opts (default=\"\" which means disabled)
Specifies the options to pass when the shared library specified in credlib is loaded and then initialized.
For the string specified in this option, specify the string defined by the shared library.
.TP
\fB\-o\fR use_xattr (default is not handling the extended attribute)
Enable to handle the extended attribute (xattrs).
If you set this option, you can use the extended attribute.
For example, encfs and ecryptfs need to support the extended attribute.
Notice: if s3fs handles the extended attribute, s3fs can not work to copy command with preserve=mode.
.TP
\fB\-o\fR noxmlns - disable registering xml name space.
disable registering xml name space for response of ListBucketResult and ListVersionsResult etc. Default name space is looked up from "http://s3.amazonaws.com/doc/2006-03-01".
This option should not be specified now, because s3fs looks up xmlns automatically after v1.66.
.TP
\fB\-o\fR nomixupload - disable copy in multipart uploads.
Disable to use PUT (copy api) when multipart uploading large size objects.
By default, when doing multipart upload, the range of unchanged data will use PUT (copy api) whenever possible.
When nocopyapi or norenameapi is specified, use of PUT (copy api) is invalidated even if this option is not specified.
.TP
\fB\-o\fR nocopyapi - for other incomplete compatibility object storage.
For a distributed object storage which is compatibility S3 API without PUT (copy api).
If you set this option, s3fs do not use PUT with "x-amz-copy-source" (copy api). Because traffic is increased 2-3 times by this option, we do not recommend this.
.TP
\fB\-o\fR norenameapi - for other incomplete compatibility object storage.
For a distributed object storage which is compatibility S3 API without PUT (copy api).
This option is a subset of nocopyapi option. The nocopyapi option does not use copy-api for all command (ex. chmod, chown, touch, mv, etc), but this option does not use copy-api for only rename command (ex. mv).
If this option is specified with nocopyapi, then s3fs ignores it.
.TP
\fB\-o\fR use_path_request_style (use legacy API calling style)
Enable compatibility with S3-like APIs which do not support the virtual-host request style, by using the older path request style.
.TP
\fB\-o\fR listobjectsv2 (use ListObjectsV2)
Issue ListObjectsV2 instead of ListObjects, useful on object
stores without ListObjects support.
.TP
\fB\-o\fR noua (suppress User-Agent header)
Usually s3fs outputs of the User-Agent in "s3fs/<version> (commit hash <hash>; <using ssl library name>)" format.
If this option is specified, s3fs suppresses the output of the User-Agent.
.TP
\fB\-o\fR cipher_suites
Customize the list of TLS cipher suites. Expects a colon separated list of cipher suite names.
A list of available cipher suites, depending on your TLS engine, can be found on the CURL library documentation:
https://curl.haxx.se/docs/ssl-ciphers.html
.TP
\fB\-o\fR instance_name
The instance name of the current s3fs mountpoint.
This name will be added to logging messages and user agent headers sent by s3fs.
.TP
\fB\-o\fR complement_stat (complement lack of file/directory mode)
s3fs complements lack of information about file/directory mode if a file or a directory object does not have x-amz-meta-mode header.
As default, s3fs does not complements stat information for a object, then the object will not be able to be allowed to list/modify.
.TP
\fB\-o\fR compat_dir (enable support of alternative directory names)
.RS
s3fs supports two different naming schemas "dir/" and "dir" to map directory names to S3 objects and vice versa by default. As a third variant, directories can be determined indirectly if there is a file object with a path (e.g. "/dir/file") but without the parent directory. This option enables a fourth variant, "dir_$folder$", created by older applications.
.TP
S3fs uses only the first schema "dir/" to create S3 objects for directories.
.TP
The support for these different naming schemas causes an increased communication effort.
.TP
If you do not have access permissions to the bucket and specify a directory path created by a client other than s3fs for the mount point, you cannot start because the mount point directory cannot be found by s3fs. But by specifying this option, you can avoid this error.
.RE
.TP
\fB\-o\fR use_wtf8 - support arbitrary file system encoding.
S3 requires all object names to be valid UTF-8. But some
clients, notably Windows NFS clients, use their own encoding.
This option re-encodes invalid UTF-8 object names into valid
UTF-8 by mapping offending codes into a 'private' codepage of the
Unicode set.
Useful on clients not using UTF-8 as their file system encoding.
.TP
\fB\-o\fR use_session_token - indicate that session token should be provided.
If credentials are provided by environment variables this switch
forces presence check of AWS_SESSION_TOKEN variable.
Otherwise an error is returned.
.TP
\fB\-o\fR requester_pays (default is disable)
This option instructs s3fs to enable requests involving Requester Pays buckets (It includes the 'x-amz-request-payer=requester' entry in the request header).
.TP
\fB\-o\fR mime (default is "/etc/mime.types")
Specify the path of the mime.types file.
If this option is not specified, the existence of "/etc/mime.types" is checked, and that file is loaded as mime information.
If this file does not exist on macOS, then "/etc/apache2/mime.types" is checked as well.
.TP
\fB\-o\fR proxy (default="")
This option specifies a proxy to S3 server.
Specify the proxy with '[<scheme://]hostname(fqdn)[:<port>]' formatted.
'<schema>://' can be omitted, and 'http://' is used when omitted.
Also, ':<port>' can also be omitted. If omitted, port 443 is used for HTTPS schema, and port 1080 is used otherwise.
This option is the same as the curl command's '--proxy(-x)' option and libcurl's 'CURLOPT_PROXY' flag.
This option is equivalent to and takes precedence over the environment variables 'http_proxy', 'all_proxy', etc.
.TP
\fB\-o\fR proxy_cred_file (default="")
This option specifies the file that describes the username and passphrase for authentication of the proxy when the HTTP schema proxy is specified by the 'proxy' option.
Username and passphrase are valid only for HTTP schema.
If the HTTP proxy does not require authentication, this option is not required.
Separate the username and passphrase with a ':' character and specify each as a URL-encoded string.
.TP
\fB\-o\fR ipresolve (default="whatever")
Select what type of IP addresses to use when establishing a connection.
Default('whatever') can use addresses of all IP versions(IPv4 and IPv6) that your system allows.
If you specify 'IPv4', only IPv4 addresses are used.
And when 'IPv6' is specified, only IPv6 addresses will be used.
.TP
\fB\-o\fR logfile - specify the log output file.
s3fs outputs the log file to syslog. Alternatively, if s3fs is started with the "-f" option specified, the log will be output to the stdout/stderr.
You can use this option to specify the log file that s3fs outputs.
If you specify a log file with this option, it will reopen the log file when s3fs receives a SIGHUP signal. You can use the SIGHUP signal for log rotation.
.TP
\fB\-o\fR dbglevel (default="crit")
Set the debug message level. set value as crit (critical), err (error), warn (warning), info (information) to debug level. default debug level is critical.
If s3fs run with "-d" option, the debug level is set information.
When s3fs catch the signal SIGUSR2, the debug level is bump up.
.TP
\fB\-o\fR curldbg - put curl debug message
Put the debug message from libcurl when this option is specified.
Specify "normal" or "body" for the parameter.
If the parameter is omitted, it is the same as "normal".
If "body" is specified, some API communication body data will be output in addition to the debug message output as "normal".
.TP
\fB\-o\fR no_time_stamp_msg - no time stamp in debug message
The time stamp is output to the debug message by default.
If this option is specified, the time stamp will not be output in the debug message.
It is the same even if the environment variable "S3FS_MSGTIMESTAMP" is set to "no".
.TP
\fB\-o\fR set_check_cache_sigusr1 (default is stdout)
If the cache is enabled, you can check the integrity of the cache file and the cache file's stats info file.
This option is specified and when sending the SIGUSR1 signal to the s3fs process checks the cache status at that time.
This option can take a file path as parameter to output the check result to that file.
The file path parameter can be omitted. If omitted, the result will be output to stdout or syslog.
.TP
\fB\-o\fR update_parent_dir_stat (default is disable)
The parent directory's mtime and ctime are updated when a file or directory is created or deleted (when the parent directory's inode is updated).
By default, parent directory statistics are not updated.
.SS "utility mode options"
.TP
\fB\-u\fR or \fB\-\-incomplete\-mpu\-list\fR
Lists multipart incomplete objects uploaded to the specified bucket.
.TP
\fB\-\-incomplete\-mpu\-abort\fR all or date format (default="24H")
Delete the multipart incomplete object uploaded to the specified bucket.
If "all" is specified for this option, all multipart incomplete objects will be deleted.
If you specify no argument as an option, objects older than 24 hours (24H) will be deleted (This is the default value).
You can specify an optional date format.
It can be specified as year, month, day, hour, minute, second, and it is expressed as "Y", "M", "D", "h", "m", "s" respectively.
For example, "1Y6M10D12h30m30s".
.SH FUSE/MOUNT OPTIONS
.TP
Most of the generic mount options described in 'man mount' are supported (ro, rw, suid, nosuid, dev, nodev, exec, noexec, atime, noatime, sync, async, dirsync). Filesystems are mounted with '\-onodev,nosuid' by default, which can only be overridden by a privileged user.
.TP
There are many FUSE specific mount options that can be specified. e.g. allow_other. See the FUSE README for the full set.
.SH SERVER URL/REQUEST STYLE
Be careful when specifying the server endpoint(URL).
.TP
If your bucket name contains dots("."), you should use the path request style(using "use_path_request_style" option).
.TP
Also, if you are using a server other than Amazon S3, you need to specify the endpoint with the "url" option. At that time, depending on the server you are using, you may have to specify the path request style("use_path_request_style" option).
.SH LOCAL STORAGE CONSUMPTION
.TP
s3fs requires local caching for operation. You can enable a local cache with "\-o use_cache" or s3fs uses temporary files to cache pending requests to s3.
.TP
Apart from the requirements discussed below, it is recommended to keep enough cache resp. temporary storage to allow one copy each of all files open for reading and writing at any one time.
.TP
.SS Local cache with \[dq]\-o use_cache\[dq]
.TP
s3fs automatically maintains a local cache of files. The cache folder is specified by the parameter of "\-o use_cache". It is only a local cache that can be deleted at any time. s3fs rebuilds it if necessary.
.TP
Whenever s3fs needs to read or write a file on S3, it first creates the file in the cache directory and operates on it.
.TP
The amount of local cache storage used can be indirectly controlled with "\-o ensure_diskfree".
.TP
.SS Without local cache
.TP
Since s3fs always requires some storage space for operation, it creates temporary files to store incoming write requests until the required s3 request size is reached and the segment has been uploaded. After that, this data is truncated in the temporary file to free up storage space.
.TP
Per file you need at least twice the part size (default 5MB or "-o multipart_size") for writing multipart requests or space for the whole file if single requests are enabled ("\-o nomultipart").
.SH PERFORMANCE CONSIDERATIONS
.TP
This section discusses settings to improve s3fs performance.
.TP
In most cases, backend performance cannot be controlled and is therefore not part of this discussion.
.TP
Details of the local storage usage is discussed in "LOCAL STORAGE CONSUMPTION".
.TP
.SS CPU and Memory Consumption
.TP
s3fs is a multi-threaded application. Depending on the workload it may use multiple CPUs and a certain amount of memory. You can monitor the CPU and memory consumption with the "top" utility.
.TP
.SS Performance of S3 requests
.TP
s3fs provides several options (e.g. "max_thread_count" option) to control behaviour and thus indirectly the performance. The possible combinations of these options in conjunction with the various S3 backends are so varied that there is no individual recommendation other than the default values. Improved individual settings can be found by testing and measuring.
.TP
The two options "Enable negative cache" ("\-o enable_negative_cache") and "Disable support of alternative directory names" ("\-o notsup_compat_dir") can be used to control shared access to the same bucket by different applications:
.TP
.IP \[bu]
Enable negative cache ("\-o enable_negative_cache")
.RS
.TP
If a bucket is used exclusively by an s3fs instance, you can enable the cache for non-existent files and directories with "\-o enable_negative_cache". This eliminates repeated requests to check the existence of an object, saving time and possibly money.
.RE
.IP \[bu]
Enable support of alternative directory names ("\-o compat_dir")
.RS
.TP
s3fs recognizes "dir/" objects as directories. Clients other than s3fs may use "dir", "dir_$folder$" objects as directories, or directory objects may not exist. In order for s3fs to recognize these as directories, you can specify the "compat_dir" option.
.RE
.IP \[bu]
Completion of file and directory information ("\-o complement_stat")
.RS
.TP
s3fs uses the "x-amz-meta-mode header" to determine if an object is a file or a directory. For this reason, objects that do not have the "x-amz-meta-mode header" may not produce the expected results(The directory cannot be displayed, etc.). By specifying the "complement_stat" option, s3fs can automatically complete this missing attribute information, and you can get the expected results.
.RE
.SH NOTES
.TP
The maximum size of objects that s3fs can handle depends on Amazon S3. For example, up to 5 GB when using single PUT API. And up to 5 TB is supported when Multipart Upload API is used.
.TP
s3fs leverages /etc/mime.types to "guess" the "correct" content-type based on file name extension. This means that you can copy a website to S3 and serve it up directly from S3 with correct content-types!
.SH SEE ALSO
fuse(8), mount(8), fusermount(1), fstab(5)
.SH BUGS
Due to S3's "eventual consistency" limitations, file creation can and will occasionally fail. Even after a successful create, subsequent reads can fail for an indeterminate time, even after one or more successful reads. Create and read enough files and you will eventually encounter this failure. This is not a flaw in s3fs and it is not something a FUSE wrapper like s3fs can work around. The retries option does not address this issue. Your application must either tolerate or compensate for these failures, for example by retrying creates or reads.
.SH AUTHOR
s3fs has been written by Randy Rizun <rrizun@gmail.com>.

View File

@ -21,24 +21,98 @@ bin_PROGRAMS=s3fs
AM_CPPFLAGS = $(DEPS_CFLAGS)
if USE_GNUTLS_NETTLE
AM_CPPFLAGS += -DUSE_GNUTLS_NETTLE
AM_CPPFLAGS += -DUSE_GNUTLS_NETTLE
endif
if USE_SSL_OPENSSL_30
AM_CPPFLAGS += -DUSE_OPENSSL_30
endif
s3fs_SOURCES = s3fs.cpp s3fs.h curl.cpp curl.h cache.cpp cache.h string_util.cpp string_util.h s3fs_util.cpp s3fs_util.h fdcache.cpp fdcache.h common_auth.cpp s3fs_auth.h addhead.cpp addhead.h common.h
s3fs_SOURCES = \
s3fs.cpp \
s3fs_global.cpp \
s3fs_help.cpp \
s3fs_logger.cpp \
s3fs_xml.cpp \
metaheader.cpp \
mpu_util.cpp \
curl.cpp \
curl_share.cpp \
curl_util.cpp \
s3objlist.cpp \
cache.cpp \
cache_node.cpp \
string_util.cpp \
s3fs_cred.cpp \
s3fs_util.cpp \
s3fs_threadreqs.cpp \
fdcache.cpp \
fdcache_entity.cpp \
fdcache_page.cpp \
fdcache_stat.cpp \
fdcache_auto.cpp \
fdcache_fdinfo.cpp \
fdcache_pseudofd.cpp \
fdcache_untreated.cpp \
filetimes.cpp \
addhead.cpp \
sighandlers.cpp \
threadpoolman.cpp \
syncfiller.cpp \
common_auth.cpp
if USE_SSL_OPENSSL
s3fs_SOURCES += openssl_auth.cpp
s3fs_SOURCES += openssl_auth.cpp
endif
if USE_SSL_GNUTLS
s3fs_SOURCES += gnutls_auth.cpp
s3fs_SOURCES += gnutls_auth.cpp
endif
if USE_SSL_NSS
s3fs_SOURCES += nss_auth.cpp
s3fs_SOURCES += nss_auth.cpp
endif
s3fs_LDADD = $(DEPS_LIBS)
noinst_PROGRAMS = test_string_util
noinst_PROGRAMS = \
test_curl_util \
test_page_list \
test_string_util
test_string_util_SOURCES = string_util.cpp test_string_util.cpp test_util.h
test_curl_util_SOURCES = common_auth.cpp curl_util.cpp string_util.cpp test_curl_util.cpp s3fs_global.cpp s3fs_logger.cpp
if USE_SSL_OPENSSL
test_curl_util_SOURCES += openssl_auth.cpp
endif
if USE_SSL_GNUTLS
test_curl_util_SOURCES += gnutls_auth.cpp
endif
if USE_SSL_NSS
test_curl_util_SOURCES += nss_auth.cpp
endif
TESTS = test_string_util
test_curl_util_LDADD = $(DEPS_LIBS)
test_page_list_SOURCES = \
fdcache_page.cpp \
s3fs_global.cpp \
s3fs_logger.cpp \
string_util.cpp \
test_page_list.cpp
test_string_util_SOURCES = string_util.cpp test_string_util.cpp s3fs_logger.cpp
TESTS = \
test_curl_util \
test_page_list \
test_string_util
clang-tidy:
clang-tidy -extra-arg-before=-xc++ -extra-arg=-std=@CPP_VERSION@ \
*.h $(s3fs_SOURCES) test_curl_util.cpp test_page_list.cpp test_string_util.cpp \
-- $(DEPS_CFLAGS) $(CPPFLAGS)
#
# Local variables:
# tab-width: 4
# c-basic-offset: 4
# End:
# vim600: noexpandtab sw=4 ts=4 fdm=marker
# vim<600: noexpandtab sw=4 ts=4
#

View File

@ -1,7 +1,7 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright 2007-2008 Randy Rizun <rrizun@gmail.com>
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -18,30 +18,25 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <assert.h>
#include <curl/curl.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <fstream>
#include <string>
#include <map>
#include <list>
#include <strings.h>
#include <utility>
#include <vector>
#include "common.h"
#include "addhead.h"
#include "curl.h"
#include "s3fs.h"
using namespace std;
#include "addhead.h"
#include "curl_util.h"
#include "s3fs_logger.h"
//-------------------------------------------------------------------
// Symbols
//-------------------------------------------------------------------
#define ADD_HEAD_REGEX "reg:"
static constexpr char ADD_HEAD_REGEX[] = "reg:";
//-------------------------------------------------------------------
// Class AdditionalHeader
@ -53,227 +48,195 @@ AdditionalHeader AdditionalHeader::singleton;
//-------------------------------------------------------------------
AdditionalHeader::AdditionalHeader()
{
if(this == AdditionalHeader::get()){
is_enable = false;
}else{
assert(false);
}
if(this == AdditionalHeader::get()){
is_enable = false;
}else{
abort();
}
}
AdditionalHeader::~AdditionalHeader()
{
if(this == AdditionalHeader::get()){
Unload();
}else{
assert(false);
}
if(this == AdditionalHeader::get()){
Unload();
}else{
abort();
}
}
bool AdditionalHeader::Load(const char* file)
{
if(!file){
S3FS_PRN_WARN("file is NULL.");
return false;
}
Unload();
if(!file){
S3FS_PRN_WARN("file is nullptr.");
return false;
}
Unload();
ifstream AH(file);
if(!AH.good()){
S3FS_PRN_WARN("Could not open file(%s).", file);
return false;
}
// read file
string line;
PADDHEAD paddhead;
while(getline(AH, line)){
if('#' == line[0]){
continue;
}
if(0 == line.size()){
continue;
}
// load a line
stringstream ss(line);
string key(""); // suffix(key)
string head; // additional HTTP header
string value; // header value
if(0 == isblank(line[0])){
ss >> key;
}
if(ss){
ss >> head;
if(ss && static_cast<size_t>(ss.tellg()) < line.size()){
value = line.substr(static_cast<int>(ss.tellg()) + 1);
}
std::ifstream AH(file);
if(!AH.good()){
S3FS_PRN_WARN("Could not open file(%s).", file);
return false;
}
// check it
if(0 == head.size()){
if(0 == key.size()){
continue;
}
S3FS_PRN_ERR("file format error: %s key(suffix) is no HTTP header value.", key.c_str());
Unload();
return false;
// read file
std::string line;
while(getline(AH, line)){
if(line.empty()){
continue;
}
if('#' == line[0]){
continue;
}
// load a line
std::istringstream ss(line);
std::string key; // suffix(key)
std::string head; // additional HTTP header
std::string value; // header value
if(0 == isblank(line[0])){
ss >> key;
}
if(ss){
ss >> head;
if(ss && static_cast<size_t>(ss.tellg()) < line.size()){
value = line.substr(static_cast<int>(ss.tellg()) + 1);
}
}
// check it
if(head.empty()){
if(key.empty()){
continue;
}
S3FS_PRN_ERR("file format error: %s key(suffix) is no HTTP header value.", key.c_str());
Unload();
return false;
}
if(0 == strncasecmp(key.c_str(), ADD_HEAD_REGEX, strlen(ADD_HEAD_REGEX))){
// regex
if(key.size() <= strlen(ADD_HEAD_REGEX)){
S3FS_PRN_ERR("file format error: %s key(suffix) does not have key std::string.", key.c_str());
continue;
}
key.erase(0, strlen(ADD_HEAD_REGEX));
// compile
RegexPtr preg(new regex_t, regfree);
int result;
if(0 != (result = regcomp(preg.get(), key.c_str(), REG_EXTENDED | REG_NOSUB))){ // we do not need matching info
char errbuf[256];
regerror(result, preg.get(), errbuf, sizeof(errbuf));
S3FS_PRN_ERR("failed to compile regex from %s key by %s.", key.c_str(), errbuf);
continue;
}
addheadlist.emplace_back(std::move(preg), key, head, value);
}else{
// not regex, directly comparing
addheadlist.emplace_back(RegexPtr(nullptr, regfree), key, head, value);
}
// set flag
is_enable = true;
}
paddhead = new ADDHEAD;
if(0 == strncasecmp(key.c_str(), ADD_HEAD_REGEX, strlen(ADD_HEAD_REGEX))){
// regex
if(key.size() <= strlen(ADD_HEAD_REGEX)){
S3FS_PRN_ERR("file format error: %s key(suffix) does not have key string.", key.c_str());
continue;
}
key = key.substr(strlen(ADD_HEAD_REGEX));
// compile
regex_t* preg = new regex_t;
int result;
char errbuf[256];
if(0 != (result = regcomp(preg, key.c_str(), REG_EXTENDED | REG_NOSUB))){ // we do not need matching info
regerror(result, preg, errbuf, sizeof(errbuf));
S3FS_PRN_ERR("failed to compile regex from %s key by %s.", key.c_str(), errbuf);
delete preg;
delete paddhead;
continue;
}
// set
paddhead->pregex = preg;
paddhead->basestring = key;
paddhead->headkey = head;
paddhead->headvalue = value;
}else{
// not regex, directly comparing
paddhead->pregex = NULL;
paddhead->basestring = key;
paddhead->headkey = head;
paddhead->headvalue = value;
}
// add list
addheadlist.push_back(paddhead);
// set flag
if(!is_enable){
is_enable = true;
}
}
return true;
return true;
}
void AdditionalHeader::Unload(void)
void AdditionalHeader::Unload()
{
is_enable = false;
is_enable = false;
for(addheadlist_t::iterator iter = addheadlist.begin(); iter != addheadlist.end(); iter = addheadlist.erase(iter)){
PADDHEAD paddhead = *iter;
if(paddhead){
if(paddhead->pregex){
regfree(paddhead->pregex);
delete paddhead->pregex;
}
delete paddhead;
}
}
addheadlist.clear();
}
bool AdditionalHeader::AddHeader(headers_t& meta, const char* path) const
{
if(!is_enable){
return true;
}
if(!path){
S3FS_PRN_WARN("path is NULL.");
return false;
}
size_t pathlength = strlen(path);
// loop
//
// [NOTE]
// Because to allow duplicate key, and then scanning the entire table.
//
for(addheadlist_t::const_iterator iter = addheadlist.begin(); iter != addheadlist.end(); ++iter){
const PADDHEAD paddhead = *iter;
if(!paddhead){
continue;
if(!is_enable){
return true;
}
if(!path){
S3FS_PRN_WARN("path is nullptr.");
return false;
}
if(paddhead->pregex){
// regex
regmatch_t match; // not use
if(0 == regexec(paddhead->pregex, path, 1, &match, 0)){
// match -> adding header
meta[paddhead->headkey] = paddhead->headvalue;
}
}else{
// directly comparing
if(paddhead->basestring.length() < pathlength){
if(0 == paddhead->basestring.length() || 0 == strcmp(&path[pathlength - paddhead->basestring.length()], paddhead->basestring.c_str())){
// match -> adding header
meta[paddhead->headkey] = paddhead->headvalue;
size_t pathlength = strlen(path);
// loop
//
// [NOTE]
// Because to allow duplicate key, and then scanning the entire table.
//
for(auto iter = addheadlist.cbegin(); iter != addheadlist.cend(); ++iter){
const add_header *paddhead = &*iter;
if(paddhead->pregex){
// regex
regmatch_t match; // not use
if(0 == regexec(paddhead->pregex.get(), path, 1, &match, 0)){
// match -> adding header
meta[paddhead->headkey] = paddhead->headvalue;
}
}else{
// directly comparing
if(paddhead->basestring.length() < pathlength){
if(paddhead->basestring.empty() || paddhead->basestring == &path[pathlength - paddhead->basestring.length()]){
// match -> adding header
meta[paddhead->headkey] = paddhead->headvalue;
}
}
}
}
}
}
return true;
return true;
}
struct curl_slist* AdditionalHeader::AddHeader(struct curl_slist* list, const char* path) const
{
headers_t meta;
headers_t meta;
if(!AddHeader(meta, path)){
if(!AddHeader(meta, path)){
return list;
}
for(auto iter = meta.cbegin(); iter != meta.cend(); ++iter){
// Adding header
list = curl_slist_sort_insert(list, iter->first.c_str(), iter->second.c_str());
}
meta.clear();
return list;
}
for(headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter){
// Adding header
list = curl_slist_sort_insert(list, iter->first.c_str(), iter->second.c_str());
}
meta.clear();
S3FS_MALLOCTRIM(0);
return list;
}
bool AdditionalHeader::Dump(void) const
bool AdditionalHeader::Dump() const
{
if(!IS_S3FS_LOG_DBG()){
return true;
}
stringstream ssdbg;
int cnt = 1;
ssdbg << "Additional Header list[" << addheadlist.size() << "] = {" << endl;
for(addheadlist_t::const_iterator iter = addheadlist.begin(); iter != addheadlist.end(); ++iter, ++cnt){
const PADDHEAD paddhead = *iter;
ssdbg << " [" << cnt << "] = {" << endl;
if(paddhead){
if(paddhead->pregex){
ssdbg << " type\t\t--->\tregex" << endl;
}else{
ssdbg << " type\t\t--->\tsuffix matching" << endl;
}
ssdbg << " base string\t--->\t" << paddhead->basestring << endl;
ssdbg << " add header\t--->\t" << paddhead->headkey << ": " << paddhead->headvalue << endl;
if(!S3fsLog::IsS3fsLogDbg()){
return true;
}
std::ostringstream ssdbg;
int cnt = 1;
ssdbg << "Additional Header list[" << addheadlist.size() << "] = {" << std::endl;
for(auto iter = addheadlist.cbegin(); iter != addheadlist.cend(); ++iter, ++cnt){
const add_header *paddhead = &*iter;
ssdbg << " [" << cnt << "] = {" << std::endl;
if(paddhead->pregex){
ssdbg << " type\t\t--->\tregex" << std::endl;
}else{
ssdbg << " type\t\t--->\tsuffix matching" << std::endl;
}
ssdbg << " base std::string\t--->\t" << paddhead->basestring << std::endl;
ssdbg << " add header\t--->\t" << paddhead->headkey << ": " << paddhead->headvalue << std::endl;
ssdbg << " }" << std::endl;
}
ssdbg << " }" << endl;
}
ssdbg << "}" << endl;
ssdbg << "}" << std::endl;
// print all
S3FS_PRN_DBG("%s", ssdbg.str().c_str());
// print all
S3FS_PRN_DBG("%s", ssdbg.str().c_str());
return true;
return true;
}
/*
@ -281,6 +244,6 @@ bool AdditionalHeader::Dump(void) const
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

View File

@ -1,7 +1,7 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright 2007-2008 Randy Rizun <rrizun@gmail.com>
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -21,41 +21,69 @@
#ifndef S3FS_ADDHEAD_H_
#define S3FS_ADDHEAD_H_
#include <memory>
#include <regex.h>
#include <string>
#include <utility>
#include <vector>
#include "metaheader.h"
//----------------------------------------------
// class AdditionalHeader
// Structure / Typedef
//----------------------------------------------
typedef struct add_header{
regex_t* pregex; // not NULL means using regex, NULL means comparing suffix directly.
std::string basestring;
std::string headkey;
std::string headvalue;
}ADDHEAD, *PADDHEAD;
typedef std::unique_ptr<regex_t, decltype(&regfree)> RegexPtr;
typedef std::vector<PADDHEAD> addheadlist_t;
struct add_header{
add_header(RegexPtr pregex, std::string basestring, std::string headkey, std::string headvalue)
: pregex(std::move(pregex))
, basestring(std::move(basestring))
, headkey(std::move(headkey))
, headvalue(std::move(headvalue))
{}
add_header(const add_header&) = delete;
add_header(add_header&& val) = default;
add_header& operator=(const add_header&) = delete;
add_header& operator=(add_header&&) = delete;
RegexPtr pregex; // not nullptr means using regex, nullptr means comparing suffix directly.
std::string basestring;
std::string headkey;
std::string headvalue;
};
typedef std::vector<add_header> addheadlist_t;
//----------------------------------------------
// Class AdditionalHeader
//----------------------------------------------
class AdditionalHeader
{
private:
static AdditionalHeader singleton;
bool is_enable;
addheadlist_t addheadlist;
private:
static AdditionalHeader singleton;
bool is_enable;
addheadlist_t addheadlist;
protected:
AdditionalHeader();
~AdditionalHeader();
protected:
AdditionalHeader();
~AdditionalHeader();
public:
// Reference singleton
static AdditionalHeader* get(void) { return &singleton; }
public:
AdditionalHeader(const AdditionalHeader&) = delete;
AdditionalHeader(AdditionalHeader&&) = delete;
AdditionalHeader& operator=(const AdditionalHeader&) = delete;
AdditionalHeader& operator=(AdditionalHeader&&) = delete;
bool Load(const char* file);
void Unload(void);
// Reference singleton
static AdditionalHeader* get() { return &singleton; }
bool AddHeader(headers_t& meta, const char* path) const;
struct curl_slist* AddHeader(struct curl_slist* list, const char* path) const;
bool Dump(void) const;
bool Load(const char* file);
void Unload();
bool AddHeader(headers_t& meta, const char* path) const;
struct curl_slist* AddHeader(struct curl_slist* list, const char* path) const;
bool Dump() const;
};
#endif // S3FS_ADDHEAD_H_
@ -65,6 +93,6 @@ class AdditionalHeader
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

View File

@ -1,7 +1,7 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright 2007-2008 Randy Rizun <rrizun@gmail.com>
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -18,600 +18,431 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#ifndef HAVE_CLOCK_GETTIME
#include <sys/time.h>
#endif
#include <unistd.h>
#include <stdint.h>
#include <pthread.h>
#include <string.h>
#include <assert.h>
#include <syslog.h>
#include <string>
#include <map>
#include <vector>
#include <algorithm>
#include <list>
#include <cerrno>
#include <cstdlib>
#include <mutex>
#include <string>
#include <sys/stat.h>
#include <utility>
#include <vector>
#include "cache.h"
#include "s3fs.h"
#include "s3fs_logger.h"
#include "s3fs_util.h"
#include "cache.h"
#include "string_util.h"
using namespace std;
//-------------------------------------------------------------------
// Utility
//-------------------------------------------------------------------
#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 0
#endif
#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC CLOCK_REALTIME
#endif
#ifndef CLOCK_MONOTONIC_COARSE
#define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC
#endif
#ifndef HAVE_CLOCK_GETTIME
static int clock_gettime(int clk_id, struct timespec* ts)
{
struct timeval now;
if(0 != gettimeofday(&now, NULL)){
return -1;
}
ts->tv_sec = now.tv_sec;
ts->tv_nsec = now.tv_usec * 1000;
return 0;
}
#endif
inline void SetStatCacheTime(struct timespec& ts)
{
if(-1 == clock_gettime(CLOCK_MONOTONIC_COARSE, &ts)){
ts.tv_sec = time(NULL);
ts.tv_nsec = 0;
}
}
inline void InitStatCacheTime(struct timespec& ts)
{
ts.tv_sec = 0;
ts.tv_nsec = 0;
}
inline int CompareStatCacheTime(struct timespec& ts1, struct timespec& ts2)
{
// return -1: ts1 < ts2
// 0: ts1 == ts2
// 1: ts1 > ts2
if(ts1.tv_sec < ts2.tv_sec){
return -1;
}else if(ts1.tv_sec > ts2.tv_sec){
return 1;
}else{
if(ts1.tv_nsec < ts2.tv_nsec){
return -1;
}else if(ts1.tv_nsec > ts2.tv_nsec){
return 1;
}
}
return 0;
}
inline bool IsExpireStatCacheTime(const struct timespec& ts, const time_t& expire)
{
struct timespec nowts;
SetStatCacheTime(nowts);
return ((ts.tv_sec + expire) < nowts.tv_sec);
}
//
// For cache out
//
typedef std::vector<stat_cache_t::iterator> statiterlist_t;
struct sort_statiterlist{
// ascending order
bool operator()(const stat_cache_t::iterator& src1, const stat_cache_t::iterator& src2) const
{
int result = CompareStatCacheTime(src1->second->cache_date, src2->second->cache_date);
if(0 == result){
if(src1->second->hit_count < src2->second->hit_count){
result = -1;
}
}
return (result < 0);
}
};
//-------------------------------------------------------------------
// Static
//-------------------------------------------------------------------
StatCache StatCache::singleton;
pthread_mutex_t StatCache::stat_cache_lock;
std::mutex StatCache::stat_cache_lock;
//-------------------------------------------------------------------
// Constructor/Destructor
//-------------------------------------------------------------------
StatCache::StatCache() : IsExpireTime(false), ExpireTime(0), CacheSize(1000), IsCacheNoObject(false)
StatCache::StatCache() : pMountPointDir(nullptr), CacheSize(100'000)
{
if(this == StatCache::getStatCacheData()){
stat_cache.clear();
pthread_mutex_init(&(StatCache::stat_cache_lock), NULL);
}else{
assert(false);
}
if(this == StatCache::getStatCacheData()){
pMountPointDir = std::make_shared<DirStatCache>("/");
}else{
abort();
}
}
StatCache::~StatCache()
{
if(this == StatCache::getStatCacheData()){
Clear();
pthread_mutex_destroy(&(StatCache::stat_cache_lock));
}else{
assert(false);
}
if(this != StatCache::getStatCacheData()){
abort();
}
}
//-------------------------------------------------------------------
// Methods
//-------------------------------------------------------------------
unsigned long StatCache::GetCacheSize(void) const
unsigned long StatCache::GetCacheSize() const
{
return CacheSize;
return CacheSize;
}
unsigned long StatCache::SetCacheSize(unsigned long size)
{
unsigned long old = CacheSize;
CacheSize = size;
return old;
unsigned long old = CacheSize;
CacheSize = size;
return old;
}
time_t StatCache::GetExpireTime(void) const
bool StatCache::GetStat(const std::string& key, struct stat* pstbuf, headers_t* pmeta, objtype_t* ptype, const char* petag)
{
return (IsExpireTime ? ExpireTime : (-1));
}
const std::lock_guard<std::mutex> lock(StatCache::stat_cache_lock);
time_t StatCache::SetExpireTime(time_t expire)
{
time_t old = ExpireTime;
ExpireTime = expire;
IsExpireTime = true;
return old;
}
time_t StatCache::UnsetExpireTime(void)
{
time_t old = IsExpireTime ? ExpireTime : (-1);
ExpireTime = 0;
IsExpireTime = false;
return old;
}
bool StatCache::SetCacheNoObject(bool flag)
{
bool old = IsCacheNoObject;
IsCacheNoObject = flag;
return old;
}
void StatCache::Clear(void)
{
pthread_mutex_lock(&StatCache::stat_cache_lock);
for(stat_cache_t::iterator iter = stat_cache.begin(); iter != stat_cache.end(); stat_cache.erase(iter++)){
if((*iter).second){
delete (*iter).second;
}
}
S3FS_MALLOCTRIM(0);
pthread_mutex_unlock(&StatCache::stat_cache_lock);
}
bool StatCache::GetStat(string& key, struct stat* pst, headers_t* meta, bool overcheck, const char* petag, bool* pisforce)
{
bool is_delete_cache = false;
string strpath = key;
pthread_mutex_lock(&StatCache::stat_cache_lock);
stat_cache_t::iterator iter = stat_cache.end();
if(overcheck && '/' != strpath[strpath.length() - 1]){
strpath += "/";
iter = stat_cache.find(strpath.c_str());
}
if(iter == stat_cache.end()){
strpath = key;
iter = stat_cache.find(strpath.c_str());
}
if(iter != stat_cache.end() && (*iter).second){
stat_cache_entry* ent = (*iter).second;
if(!IsExpireTime || !IsExpireStatCacheTime(ent->cache_date, ExpireTime)){
if(ent->noobjcache){
pthread_mutex_unlock(&StatCache::stat_cache_lock);
if(!IsCacheNoObject){
// need to delete this cache.
DelStat(strpath);
}else{
// noobjcache = true means no object.
}
// find key(path) in cache
auto pStatCache = pMountPointDir->Find(key, petag);
if(!pStatCache){
return false;
}
// hit without checking etag
string stretag;
if(petag){
// find & check ETag
for(headers_t::iterator iter = ent->meta.begin(); iter != ent->meta.end(); ++iter){
string tag = lower(iter->first);
if(tag == "etag"){
stretag = iter->second;
if('\0' != petag[0] && 0 != strcmp(petag, stretag.c_str())){
is_delete_cache = true;
}
// [NOTE]
// The object type will always be set.
// This is useful for determining cache types(such as Negative type)
// where the caller receives false.
//
if(ptype){
*ptype = pStatCache->GetType();
}
// check negative cache
if(pStatCache->isNegative()){
pStatCache->IncrementHitCount();
S3FS_PRN_DBG("Hit negative stat cache [path=%s][hit count=%lu]", key.c_str(), pStatCache->GetHitCount());
return false;
}
// set data
if(!pStatCache->Get(pmeta, pstbuf)){
return false;
}
// hit cache
S3FS_PRN_DBG("Hit stat cache [path=%s][hit count=%lu]", key.c_str(), pStatCache->GetHitCount());
// for debug
//pMountPointDir->Dump(true);
return true;
}
bool StatCache::AddStatHasLock(const std::string& key, const struct stat* pstbuf, const headers_t* pmeta, objtype_t type, bool notruncate)
{
// Add(overwrite) new cache
if(!pMountPointDir->Add(key, pstbuf, pmeta, type, notruncate)){
S3FS_PRN_DBG("failed to add stat cache entry[path=%s]", key.c_str());
return false;
}
// Truncate cache(if over cache size)
if(TruncateCacheHasLock(true)){
S3FS_PRN_DBG("Some expired caches have been truncated.");
}
S3FS_PRN_INFO3("add stat cache entry[path=%s]", key.c_str());
// for debug
//pMountPointDir->Dump(true);
return true;
}
bool StatCache::AddStat(const std::string& key, const struct stat& stbuf, const headers_t& meta, objtype_t type, bool notruncate)
{
// [NOTE]
// If notruncate=true, force caching
//
if(GetCacheSize() < 1 && !notruncate){
return true;
}
const std::lock_guard<std::mutex> lock(StatCache::stat_cache_lock);
return AddStatHasLock(key, &stbuf, &meta, type, notruncate);
}
bool StatCache::AddStat(const std::string& key, const struct stat& stbuf, objtype_t type, bool notruncate)
{
// [NOTE]
// If notruncate=true, force caching
//
if(GetCacheSize() < 1 && !notruncate){
return true;
}
const std::lock_guard<std::mutex> lock(StatCache::stat_cache_lock);
return AddStatHasLock(key, &stbuf, nullptr, type, notruncate);
}
// [NOTE]
// Updates only meta data if cached data exists.
// And when these are updated, it also updates the cache time.
//
// Since the file mode may change while the file is open, it is
// updated as well.
//
bool StatCache::UpdateStat(const std::string& key, const struct stat& stbuf, const headers_t& meta)
{
const std::lock_guard<std::mutex> lock(StatCache::stat_cache_lock);
// search key cache
auto pCache = pMountPointDir->Find(key);
if(!pCache){
// Not found cache
return false;
}
if(!pCache->Update(stbuf, meta)){
S3FS_PRN_DBG("failed to update stat cache entry[path=%s]", key.c_str());
return false;
}
S3FS_PRN_INFO3("update stat cache entry[path=%s]", key.c_str());
// for debug
//pMountPointDir->Dump(true);
return true;
}
bool StatCache::AddNegativeStat(const std::string& key)
{
const std::lock_guard<std::mutex> lock(StatCache::stat_cache_lock);
// [NOTE]
// Since Negative Cache exists regardless of cache size, first delete
// the cache if it exists.
//
auto pCache = pMountPointDir->Find(key);
if(pCache){
pMountPointDir->RemoveChild(key);
}
if(GetCacheSize() < 1){
S3FS_PRN_INFO3("failed to add negative cache entry[path=%s], but returns true.", key.c_str());
return true;
}
// Add cache
if(!pMountPointDir->Add(key, nullptr, nullptr, objtype_t::NEGATIVE)){
S3FS_PRN_INFO3("failed to add negative cache entry[path=%s]", key.c_str());
return false;
}
// Truncate cache(if over cache size)
if(TruncateCacheHasLock(true)){
S3FS_PRN_DBG("Some expired caches have been truncated.");
}
S3FS_PRN_INFO3("add negative cache entry[path=%s]", key.c_str());
// for debug
//pMountPointDir->Dump(true);
return true;
}
void StatCache::ClearNoTruncateFlag(const std::string& key)
{
const std::lock_guard<std::mutex> lock(StatCache::stat_cache_lock);
// search key cache
auto pCache = pMountPointDir->Find(key);
if(pCache){
// Clear NoTruncate Flag
pCache->ClearNoTruncate();
}
}
//
// Cache truncation will be performed if check_only_oversize_case=true
// or the cache size overflows.
//
// [NOTE]
// If there are no expired caches, no cache truncation will occur.
// Also, caches marked as NoTruncate and caches in non-empty directories
// will never be deleted.
// This behavior means that no truncation will occur and caches will
// accumulate until one of the caches expires.
//
bool StatCache::TruncateCacheHasLock(bool check_only_oversize_case)
{
if(check_only_oversize_case && StatCacheNode::GetCacheCount() <= GetCacheSize()){
return false;
}
if(!pMountPointDir->TruncateCache()){
S3FS_PRN_DBG("could not truncate any cache[current size=%lu, maximum size=%lu]", StatCacheNode::GetCacheCount(), GetCacheSize());
return false;
}
// for debug
//pMountPointDir->Dump(true);
return true;
}
bool StatCache::DelStatHasLock(const std::string& key)
{
// remove cache(can not remove mount point)
if(key == pMountPointDir->Get()){
if(!pMountPointDir->ClearData()){
S3FS_PRN_DBG("Failed to clear cache data for mount point.");
return false;
}
}else if(!pMountPointDir->RemoveChild(key)){
// not found key in cache(already removed)
S3FS_PRN_DBG("not found stat cache entry[path=%s]", key.c_str());
}else{
S3FS_PRN_INFO3("delete stat cache entry[path=%s]", key.c_str());
// for debug
//pMountPointDir->Dump(true);
}
return true;
}
bool StatCache::DelStat(const std::string& key)
{
const std::lock_guard<std::mutex> lock(StatCache::stat_cache_lock);
return DelStatHasLock(key);
}
bool StatCache::GetSymlink(const std::string& key, std::string& value)
{
if(GetCacheSize() < 1){
return true;
}
const std::lock_guard<std::mutex> lock(StatCache::stat_cache_lock);
// search key cache
auto pCache = pMountPointDir->Find(key);
if(!pCache){
// Not found cache
return false;
}
if(!pCache->isSymlink()){
// Cache object is not symlink.
//
// [NOTE]
// If updating this cache(key) as a Symlink, the caller must
// delete or overwrite it.
//
return false;
}
if(!pCache->GetExtra(value)){
return false;
}
S3FS_PRN_INFO3("get symbolic link cache entry[path=%s]", key.c_str());
// for debug
//pMountPointDir->Dump(true);
return true;
}
bool StatCache::AddSymlink(const std::string& key, const struct stat& stbuf, const headers_t& meta, const std::string& value)
{
const std::lock_guard<std::mutex> lock(StatCache::stat_cache_lock);
// find in cache
auto pCache = pMountPointDir->Find(key);
if(pCache && !pCache->isSymlink()){
// found stat cache is not symlink type, remove it.
pMountPointDir->RemoveChild(key);
pCache = pMountPointDir->Find(key); // = nullptr
}
// add new cache if not found in cache
if(!pCache){
// add symlink stat cache
if(!pMountPointDir->Add(key, &stbuf, &meta, objtype_t::SYMLINK, false)){
S3FS_PRN_DBG("failed to add symbolic link cache entry[path=%s, value=%s]", key.c_str(), value.c_str());
return false;
}
// re-get symlink stat cache
if(nullptr == (pCache = pMountPointDir->Find(key))){
S3FS_PRN_ERR("Symlink stat cache not found even though it was added[path=%s]", key.c_str());
return false;
}
}
// add(update) symlink path
if(!pCache->Update(value)){
S3FS_PRN_ERR("failed to add symbolic link cache entry[path=%s, value=%s]", key.c_str(), value.c_str());
return false;
}
// Truncate cache(if over cache size)
if(TruncateCacheHasLock(true)){
S3FS_PRN_DBG("Some expired caches have been truncated.");
}
S3FS_PRN_INFO3("add symbolic link cache entry[path=%s, value=%s]", key.c_str(), value.c_str());
// for debug
//pMountPointDir->Dump(true);
return true;
}
// [Background]
// When s3fs creates a new file, the file does not exist until the file contents
// are uploaded.(because it doesn't create a 0 byte file)
// From the time this file is created(opened) until it is uploaded(flush), it
// will have a Stat cache with the No truncate flag added.
// This avoids file not existing errors in operations such as chmod and utimens
// that occur in the short period before file upload.
// Besides this, we also need to support readdir(list_bucket), this method is
// called to maintain the cache for readdir and return its value.
//
// [NOTE]
// Add the file names under "dir" to the list.
// However, if the same file name exists in the list, it will not be added.
// "dir" must be terminated with a '/'.
//
bool StatCache::RawGetChildStats(const std::string& dir, s3obj_list_t* plist, s3obj_type_map_t* pobjmap)
{
if(dir.empty()){
return false;
}
if(!plist && !pobjmap){
return false;
}
S3FS_PRN_INFO3("get child stat cache list[path=%s]", dir.c_str());
const std::lock_guard<std::mutex> lock(StatCache::stat_cache_lock);
// [NOTE]
// Since Negative Cache exists regardless of cache size, first delete
// the cache if it exists.
//
auto pCache = pMountPointDir->Find(dir);
if(!pCache){
// not found directory stat cache
return true;
}
// get child leaf path list
s3obj_type_map_t childmap;
if(0 == pCache->GetChildMap(childmap)){
return true;
}
// merge list
for(auto iter = childmap.cbegin(); iter != childmap.cend(); ++iter){
if(plist){
if(plist->cend() == std::find(plist->cbegin(), plist->cend(), iter->first)){
plist->push_back(iter->first);
}
break;
}
}
}
if(is_delete_cache){
// not hit by different ETag
S3FS_PRN_DBG("stat cache not hit by ETag[path=%s][time=%jd.%09ld][hit count=%lu][ETag(%s)!=(%s)]",
strpath.c_str(), (intmax_t)(ent->cache_date.tv_sec), ent->cache_date.tv_nsec, ent->hit_count, petag ? petag : "null", stretag.c_str());
}else{
// hit
S3FS_PRN_DBG("stat cache hit [path=%s][time=%jd.%09ld][hit count=%lu]",
strpath.c_str(), (intmax_t)(ent->cache_date.tv_sec), ent->cache_date.tv_nsec, ent->hit_count);
if(pst!= NULL){
*pst= ent->stbuf;
if(pobjmap){
if(pobjmap->cend() == pobjmap->find(iter->first)){
(*pobjmap)[iter->first] = iter->second;
}
}
if(meta != NULL){
*meta = ent->meta;
}
if(pisforce != NULL){
(*pisforce) = ent->isforce;
}
ent->hit_count++;
SetStatCacheTime(ent->cache_date);
pthread_mutex_unlock(&StatCache::stat_cache_lock);
return true;
}
}else{
// timeout
is_delete_cache = true;
}
}
pthread_mutex_unlock(&StatCache::stat_cache_lock);
if(is_delete_cache){
DelStat(strpath);
}
return false;
}
bool StatCache::IsNoObjectCache(string& key, bool overcheck)
{
bool is_delete_cache = false;
string strpath = key;
if(!IsCacheNoObject){
return false;
}
pthread_mutex_lock(&StatCache::stat_cache_lock);
stat_cache_t::iterator iter = stat_cache.end();
if(overcheck && '/' != strpath[strpath.length() - 1]){
strpath += "/";
iter = stat_cache.find(strpath.c_str());
}
if(iter == stat_cache.end()){
strpath = key;
iter = stat_cache.find(strpath.c_str());
}
if(iter != stat_cache.end() && (*iter).second) {
if(!IsExpireTime || !IsExpireStatCacheTime((*iter).second->cache_date, ExpireTime)){
if((*iter).second->noobjcache){
// noobjcache = true means no object.
SetStatCacheTime((*iter).second->cache_date);
pthread_mutex_unlock(&StatCache::stat_cache_lock);
return true;
}
}else{
// timeout
is_delete_cache = true;
}
}
pthread_mutex_unlock(&StatCache::stat_cache_lock);
if(is_delete_cache){
DelStat(strpath);
}
return false;
}
bool StatCache::AddStat(std::string& key, headers_t& meta, bool forcedir, bool no_truncate)
{
if(!no_truncate && CacheSize< 1){
return true;
}
S3FS_PRN_INFO3("add stat cache entry[path=%s]", key.c_str());
pthread_mutex_lock(&StatCache::stat_cache_lock);
bool found = stat_cache.end() != stat_cache.find(key);
bool do_truncate = stat_cache.size() > CacheSize;
pthread_mutex_unlock(&StatCache::stat_cache_lock);
if(found){
DelStat(key.c_str());
}else{
if(do_truncate){
if(!TruncateCache()){
return false;
}
}
}
// make new
stat_cache_entry* ent = new stat_cache_entry();
if(!convert_header_to_stat(key.c_str(), meta, &(ent->stbuf), forcedir)){
delete ent;
return false;
}
ent->hit_count = 0;
ent->isforce = forcedir;
ent->noobjcache = false;
ent->notruncate = (no_truncate ? 1L : 0L);
ent->meta.clear();
SetStatCacheTime(ent->cache_date); // Set time.
//copy only some keys
for(headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter){
string tag = lower(iter->first);
string value = iter->second;
if(tag == "content-type"){
ent->meta[iter->first] = value;
}else if(tag == "content-length"){
ent->meta[iter->first] = value;
}else if(tag == "etag"){
ent->meta[iter->first] = value;
}else if(tag == "last-modified"){
ent->meta[iter->first] = value;
}else if(tag.substr(0, 5) == "x-amz"){
ent->meta[tag] = value; // key is lower case for "x-amz"
}
}
// add
pthread_mutex_lock(&StatCache::stat_cache_lock);
stat_cache_t::iterator iter = stat_cache.find(key); // recheck for same key exists
if(stat_cache.end() != iter){
if(iter->second){
delete iter->second;
}
stat_cache.erase(iter);
}
stat_cache[key] = ent;
pthread_mutex_unlock(&StatCache::stat_cache_lock);
return true;
}
bool StatCache::AddNoObjectCache(string& key)
bool StatCache::GetChildStatList(const std::string& dir, s3obj_list_t& list)
{
if(!IsCacheNoObject){
return true; // pretend successful
}
if(CacheSize < 1){
return true;
}
S3FS_PRN_INFO3("add no object cache entry[path=%s]", key.c_str());
pthread_mutex_lock(&StatCache::stat_cache_lock);
bool found = stat_cache.end() != stat_cache.find(key);
bool do_truncate = stat_cache.size() > CacheSize;
pthread_mutex_unlock(&StatCache::stat_cache_lock);
if(found){
DelStat(key.c_str());
}else{
if(do_truncate){
if(!TruncateCache()){
return false;
}
}
}
// make new
stat_cache_entry* ent = new stat_cache_entry();
memset(&(ent->stbuf), 0, sizeof(struct stat));
ent->hit_count = 0;
ent->isforce = false;
ent->noobjcache = true;
ent->notruncate = 0L;
ent->meta.clear();
SetStatCacheTime(ent->cache_date); // Set time.
// add
pthread_mutex_lock(&StatCache::stat_cache_lock);
stat_cache_t::iterator iter = stat_cache.find(key); // recheck for same key exists
if(stat_cache.end() != iter){
if(iter->second){
delete iter->second;
}
stat_cache.erase(iter);
}
stat_cache[key] = ent;
pthread_mutex_unlock(&StatCache::stat_cache_lock);
return true;
return RawGetChildStats(dir, &list, nullptr);
}
void StatCache::ChangeNoTruncateFlag(std::string key, bool no_truncate)
bool StatCache::GetChildStatMap(const std::string& dir, s3obj_type_map_t& objmap)
{
pthread_mutex_lock(&StatCache::stat_cache_lock);
stat_cache_t::iterator iter = stat_cache.find(key);
if(stat_cache.end() != iter){
stat_cache_entry* ent = iter->second;
if(ent){
if(no_truncate){
++(ent->notruncate);
}else{
if(0L < ent->notruncate){
--(ent->notruncate);
}
}
}
}
pthread_mutex_unlock(&StatCache::stat_cache_lock);
return RawGetChildStats(dir, nullptr, &objmap);
}
bool StatCache::TruncateCache(void)
void StatCache::Dump(bool detail)
{
if(stat_cache.empty()){
return true;
}
pthread_mutex_lock(&StatCache::stat_cache_lock);
// 1) erase over expire time
if(IsExpireTime){
for(stat_cache_t::iterator iter = stat_cache.begin(); iter != stat_cache.end(); ){
stat_cache_entry* entry = iter->second;
if(!entry || (0L < entry->notruncate && IsExpireStatCacheTime(entry->cache_date, ExpireTime))){
stat_cache.erase(iter++);
}else{
++iter;
}
}
}
// 2) check stat cache count
if(stat_cache.size() < CacheSize){
pthread_mutex_unlock(&StatCache::stat_cache_lock);
return true;
}
// 3) erase from the old cache in order
size_t erase_count= stat_cache.size() - CacheSize + 1;
statiterlist_t erase_iters;
for(stat_cache_t::iterator iter = stat_cache.begin(); iter != stat_cache.end(); ++iter){
// check no truncate
stat_cache_entry* ent = iter->second;
if(ent && 0L < ent->notruncate){
// skip for no truncate entry
if(0 < erase_count){
--erase_count; // decrement
}
}
// iter is not have notruncate flag
erase_iters.push_back(iter);
sort(erase_iters.begin(), erase_iters.end(), sort_statiterlist());
if(erase_count < erase_iters.size()){
erase_iters.pop_back();
}
}
for(statiterlist_t::iterator iiter = erase_iters.begin(); iiter != erase_iters.end(); ++iiter){
stat_cache_t::iterator siter = *iiter;
S3FS_PRN_DBG("truncate stat cache[path=%s]", siter->first.c_str());
stat_cache.erase(siter);
}
S3FS_MALLOCTRIM(0);
pthread_mutex_unlock(&StatCache::stat_cache_lock);
return true;
}
bool StatCache::DelStat(const char* key)
{
if(!key){
return false;
}
S3FS_PRN_INFO3("delete stat cache entry[path=%s]", key);
pthread_mutex_lock(&StatCache::stat_cache_lock);
stat_cache_t::iterator iter;
if(stat_cache.end() != (iter = stat_cache.find(string(key)))){
if((*iter).second){
delete (*iter).second;
}
stat_cache.erase(iter);
}
if(0 < strlen(key) && 0 != strcmp(key, "/")){
string strpath = key;
if('/' == strpath[strpath.length() - 1]){
// If there is "path" cache, delete it.
strpath = strpath.substr(0, strpath.length() - 1);
}else{
// If there is "path/" cache, delete it.
strpath += "/";
}
if(stat_cache.end() != (iter = stat_cache.find(strpath.c_str()))){
if((*iter).second){
delete (*iter).second;
}
stat_cache.erase(iter);
}
}
S3FS_MALLOCTRIM(0);
pthread_mutex_unlock(&StatCache::stat_cache_lock);
return true;
}
//-------------------------------------------------------------------
// Functions
//-------------------------------------------------------------------
bool convert_header_to_stat(const char* path, headers_t& meta, struct stat* pst, bool forcedir)
{
if(!path || !pst){
return false;
}
memset(pst, 0, sizeof(struct stat));
pst->st_nlink = 1; // see fuse FAQ
// mode
pst->st_mode = get_mode(meta, path, true, forcedir);
// blocks
if(S_ISREG(pst->st_mode)){
pst->st_blocks = get_blocks(pst->st_size);
}
pst->st_blksize = 4096;
// mtime
pst->st_mtime = get_mtime(meta);
// size
pst->st_size = get_size(meta);
// uid/gid
pst->st_uid = get_uid(meta);
pst->st_gid = get_gid(meta);
return true;
const std::lock_guard<std::mutex> lock(StatCache::stat_cache_lock);
pMountPointDir->Dump(detail);
}
/*
@ -619,6 +450,6 @@ bool convert_header_to_stat(const char* path, headers_t& meta, struct stat* pst,
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

View File

@ -1,7 +1,7 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright 2007-2008 Randy Rizun <rrizun@gmail.com>
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -21,115 +21,113 @@
#ifndef S3FS_CACHE_H_
#define S3FS_CACHE_H_
#include <cstring>
#include <map>
#include <mutex>
#include <string>
#include <sys/stat.h>
#include <vector>
#include "common.h"
#include "metaheader.h"
#include "s3objlist.h"
#include "cache_node.h"
//
// Struct
//
struct stat_cache_entry {
struct stat stbuf;
unsigned long hit_count;
struct timespec cache_date;
headers_t meta;
bool isforce;
bool noobjcache; // Flag: cache is no object for no listing.
unsigned long notruncate; // 0<: not remove automatically at checking truncate
stat_cache_entry() : hit_count(0), isforce(false), noobjcache(false), notruncate(0L) {
memset(&stbuf, 0, sizeof(struct stat));
cache_date.tv_sec = 0;
cache_date.tv_nsec = 0;
meta.clear();
}
};
typedef std::map<std::string, stat_cache_entry*> stat_cache_t; // key=path
//
// Class
//-------------------------------------------------------------------
// Class StatCache
//-------------------------------------------------------------------
// [NOTE] About Symbolic link cache
// The Stats cache class now also has a symbolic link cache.
// It is possible to take out the Symbolic link cache in another class,
// but the cache out etc. should be synchronized with the Stats cache
// and implemented in this class.
// Symbolic link cache size and timeout use the same settings as Stats
// cache. This simplifies user configuration, and from a user perspective,
// the symbolic link cache appears to be included in the Stats cache.
//
class StatCache
{
private:
static StatCache singleton;
static pthread_mutex_t stat_cache_lock;
stat_cache_t stat_cache;
bool IsExpireTime;
time_t ExpireTime;
unsigned long CacheSize;
bool IsCacheNoObject;
private:
static StatCache singleton;
static std::mutex stat_cache_lock;
private:
StatCache();
~StatCache();
std::shared_ptr<DirStatCache> pMountPointDir GUARDED_BY(stat_cache_lock); // Top directory = Mount point
unsigned long CacheSize;
void Clear(void);
bool GetStat(std::string& key, struct stat* pst, headers_t* meta, bool overcheck, const char* petag, bool* pisforce);
// Truncate stat cache
bool TruncateCache(void);
private:
StatCache();
~StatCache();
public:
// Reference singleton
static StatCache* getStatCacheData(void) {
return &singleton;
}
bool AddStatHasLock(const std::string& key, const struct stat* pstbuf, const headers_t* pmeta, objtype_t type, bool notruncate) REQUIRES(StatCache::stat_cache_lock);
bool TruncateCacheHasLock(bool check_only_oversize_case = true) REQUIRES(StatCache::stat_cache_lock);
bool DelStatHasLock(const std::string& key) REQUIRES(StatCache::stat_cache_lock);
bool RawGetChildStats(const std::string& dir, s3obj_list_t* plist, s3obj_type_map_t* pobjmap);
// Attribute
unsigned long GetCacheSize(void) const;
unsigned long SetCacheSize(unsigned long size);
time_t GetExpireTime(void) const;
time_t SetExpireTime(time_t expire);
time_t UnsetExpireTime(void);
bool SetCacheNoObject(bool flag);
bool EnableCacheNoObject(void) {
return SetCacheNoObject(true);
}
bool DisableCacheNoObject(void) {
return SetCacheNoObject(false);
}
bool GetCacheNoObject(void) const {
return IsCacheNoObject;
}
public:
StatCache(const StatCache&) = delete;
StatCache(StatCache&&) = delete;
StatCache& operator=(const StatCache&) = delete;
StatCache& operator=(StatCache&&) = delete;
// Get stat cache
bool GetStat(std::string& key, struct stat* pst, headers_t* meta, bool overcheck = true, bool* pisforce = NULL) {
return GetStat(key, pst, meta, overcheck, NULL, pisforce);
}
bool GetStat(std::string& key, struct stat* pst, bool overcheck = true) {
return GetStat(key, pst, NULL, overcheck, NULL, NULL);
}
bool GetStat(std::string& key, headers_t* meta, bool overcheck = true) {
return GetStat(key, NULL, meta, overcheck, NULL, NULL);
}
bool HasStat(std::string& key, bool overcheck = true) {
return GetStat(key, NULL, NULL, overcheck, NULL, NULL);
}
bool HasStat(std::string& key, const char* etag, bool overcheck = true) {
return GetStat(key, NULL, NULL, overcheck, etag, NULL);
}
// Reference singleton
static StatCache* getStatCacheData()
{
return &singleton;
}
// Cache For no object
bool IsNoObjectCache(std::string& key, bool overcheck = true);
bool AddNoObjectCache(std::string& key);
// Attribute
unsigned long GetCacheSize() const;
unsigned long SetCacheSize(unsigned long size);
// Add stat cache
bool AddStat(std::string& key, headers_t& meta, bool forcedir = false, bool no_truncate = false);
// Get stat cache
bool GetStat(const std::string& key, struct stat* pstbuf, headers_t* pmeta, objtype_t* ptype, const char* petag = nullptr);
bool GetStat(const std::string& key, struct stat* pstbuf, headers_t* pmeta)
{
return GetStat(key, pstbuf, pmeta, nullptr, nullptr);
}
bool GetStat(const std::string& key, struct stat* pstbuf, const char* petag)
{
return GetStat(key, pstbuf, nullptr, nullptr, petag);
}
bool GetStat(const std::string& key, struct stat* pstbuf)
{
return GetStat(key, pstbuf, nullptr, nullptr, nullptr);
}
bool GetStat(const std::string& key, headers_t* pmeta)
{
return GetStat(key, nullptr, pmeta, nullptr, nullptr);
}
bool HasStat(const std::string& key, const char* petag = nullptr)
{
return GetStat(key, nullptr, nullptr, nullptr, petag);
}
// Change no truncate flag
void ChangeNoTruncateFlag(std::string key, bool no_truncate);
// Add stat cache
bool AddStat(const std::string& key, const struct stat& stbuf, const headers_t& meta, objtype_t type, bool notruncate = false);
bool AddStat(const std::string& key, const struct stat& stbuf, objtype_t type, bool notruncate = false);
bool AddNegativeStat(const std::string& key);
// Delete stat cache
bool DelStat(const char* key);
bool DelStat(std::string& key) {
return DelStat(key.c_str());
}
// Update meta stats
bool UpdateStat(const std::string& key, const struct stat& stbuf, const headers_t& meta);
// Change no truncate flag
void ClearNoTruncateFlag(const std::string& key);
// Delete stat cache
bool DelStat(const std::string& key);
// Cache for symbolic link
bool GetSymlink(const std::string& key, std::string& value);
bool AddSymlink(const std::string& key, const struct stat& stbuf, const headers_t& meta, const std::string& value);
// Get List/Map
bool GetChildStatList(const std::string& dir, s3obj_list_t& list);
bool GetChildStatMap(const std::string& dir, s3obj_type_map_t& objmap);
// For debugging
void Dump(bool detail);
};
//
// Functions
//
bool convert_header_to_stat(const char* path, headers_t& meta, struct stat* pst, bool forcedir = false);
#endif // S3FS_CACHE_H_
/*
@ -137,6 +135,6 @@ bool convert_header_to_stat(const char* path, headers_t& meta, struct stat* pst,
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

1454
src/cache_node.cpp Normal file

File diff suppressed because it is too large Load Diff

360
src/cache_node.h Normal file
View File

@ -0,0 +1,360 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_CACHE_NODE_H_
#define S3FS_CACHE_NODE_H_
#include <iosfwd>
#include <memory>
#include <mutex>
#include "common.h"
#include "metaheader.h"
#include "s3objlist.h"
#include "types.h"
//-------------------------------------------------------------------
// Utilities
//-------------------------------------------------------------------
#define MAX_STAT_CACHE_COUNTER 6
constexpr int stat_counter_pos(objtype_t type)
{
if(IS_FILE_OBJ(type)){
return 1;
}else if(IS_SYMLINK_OBJ(type)){
return 2;
}else if(IS_DIR_OBJ(type)){
return 3;
}else if(IS_NEGATIVE_OBJ(type)){
return 4;
}else{ // objtype_t::UNKNOWN and other
return 0;
}
}
//-------------------------------------------------------------------
// Base Class : StatCacheNode
//-------------------------------------------------------------------
class DirStatCache;
class StatCacheNode : public std::enable_shared_from_this<StatCacheNode>
{
// [NOTE]
// As an exception, declare friends to call some protected methods from
// DirStatCache::RemoveChildHasLock and AddHasLock methods.
//
friend class DirStatCache;
protected:
// Stat cache counter(see. stat_counter_pos())
// <position>
// 0 = total node count
// 1 = file node count
// 2 = symlink node count
// 3 = directory node count
// 4 = negative cache node count
//
static std::mutex counter_lock;
static unsigned long counter[MAX_STAT_CACHE_COUNTER] GUARDED_BY(counter_lock);
static bool EnableExpireTime;
static bool IsExpireIntervalType; // if this flag is true, cache data is updated at last access time.
static time_t ExpireTime;
static bool UseNegativeCache;
static std::mutex cache_lock; // for internal data
static unsigned long DisableCheckingExpire GUARDED_BY(cache_lock); // If greater than 0, it disables the expiration check, which allows disabling checks during processing.
static struct timespec DisableExpireDate GUARDED_BY(cache_lock); // Data registered after this time will not be truncated(if 0 < DisableCheckingExpire)
private:
objtype_t cache_type GUARDED_BY(StatCacheNode::cache_lock) = objtype_t::UNKNOWN; // object type is set in the constructor(except dir).
std::string fullpath GUARDED_BY(StatCacheNode::cache_lock); // full path(This value is set only when the object is created)
unsigned long hit_count GUARDED_BY(StatCacheNode::cache_lock) = 0L; // hit count
struct timespec cache_date GUARDED_BY(StatCacheNode::cache_lock) = {0, 0}; // registration/renewal time
bool notruncate GUARDED_BY(StatCacheNode::cache_lock) = false; // If true, not remove automatically at checking truncate.
bool has_stat GUARDED_BY(StatCacheNode::cache_lock) = false; // valid stat information flag (for case only path registration and no stat information)
struct stat stbuf GUARDED_BY(StatCacheNode::cache_lock) = {}; // stat data
bool has_meta GUARDED_BY(StatCacheNode::cache_lock) = false; // valid meta headers information flag (for case only path registration and no meta headers)
headers_t meta GUARDED_BY(StatCacheNode::cache_lock); // meta list
bool has_extval GUARDED_BY(StatCacheNode::cache_lock) = false; // valid extra value flag
std::string extvalue GUARDED_BY(StatCacheNode::cache_lock); // extra value for key(ex. used for symlink)
protected:
static void IncrementCacheCount(objtype_t type);
static void DecrementCacheCount(objtype_t type);
static bool SetNegativeCache(bool flag);
static bool NeedExpireCheckHasLock(const struct timespec& ts) REQUIRES(StatCacheNode::cache_lock);
// Cache Type
bool isSameObjectTypeHasLock(objtype_t type) const REQUIRES(StatCacheNode::cache_lock);
bool isDirectoryHasLock() const REQUIRES(StatCacheNode::cache_lock);
bool isFileHasLock() const REQUIRES(StatCacheNode::cache_lock);
bool isSymlinkHasLock() const REQUIRES(StatCacheNode::cache_lock);
bool isNegativeHasLock() const REQUIRES(StatCacheNode::cache_lock);
// Clear
virtual bool ClearDataHasLock() REQUIRES(StatCacheNode::cache_lock);
virtual bool ClearHasLock() REQUIRES(StatCacheNode::cache_lock);
virtual bool RemoveChildHasLock(const std::string& strpath) REQUIRES(StatCacheNode::cache_lock);
virtual bool isRemovableHasLock() REQUIRES(StatCacheNode::cache_lock);
// Add
virtual bool AddHasLock(const std::string& strpath, const struct stat* pstat, const headers_t* pmeta, objtype_t type, bool is_notruncate) REQUIRES(StatCacheNode::cache_lock);
// Update(Set)
bool UpdateHasLock(objtype_t type) REQUIRES(StatCacheNode::cache_lock);
virtual bool UpdateHasLock(const struct stat* pstat, const headers_t* pmeta, bool clear_meta) REQUIRES(StatCacheNode::cache_lock);
virtual bool UpdateHasLock(const struct stat* pstat, bool clear_meta) REQUIRES(StatCacheNode::cache_lock);
virtual bool UpdateHasLock(bool is_notruncate) REQUIRES(StatCacheNode::cache_lock);
virtual bool UpdateHasLock(const std::string* pextvalue) REQUIRES(StatCacheNode::cache_lock);
virtual bool UpdateHasLock() REQUIRES(StatCacheNode::cache_lock);
virtual bool SetHasLock(const struct stat& stbuf, const headers_t& meta, bool is_notruncate) REQUIRES(StatCacheNode::cache_lock);
// Get
objtype_t GetTypeHasLock() const REQUIRES(StatCacheNode::cache_lock);
const std::string& GetPathHasLock() const REQUIRES(StatCacheNode::cache_lock);
bool HasStatHasLock() const REQUIRES(StatCacheNode::cache_lock);
bool HasMetaHasLock() const REQUIRES(StatCacheNode::cache_lock);
bool GetNoTruncateHasLock() const REQUIRES(StatCacheNode::cache_lock);
virtual bool GetHasLock(headers_t* pmeta, struct stat* pst) REQUIRES(StatCacheNode::cache_lock);
virtual bool GetExtraHasLock(std::string& value) REQUIRES(StatCacheNode::cache_lock);
virtual s3obj_type_map_t::size_type GetChildMapHasLock(s3obj_type_map_t& childmap) REQUIRES(StatCacheNode::cache_lock);
// Find
virtual bool CheckETagValueHasLock(const char* petagval) const REQUIRES(StatCacheNode::cache_lock);
virtual std::shared_ptr<StatCacheNode> FindHasLock(const std::string& strpath, const char* petagval, bool& needTruncate) REQUIRES(StatCacheNode::cache_lock);
// Cache out
bool IsExpireStatCacheTimeHasLock() const REQUIRES(StatCacheNode::cache_lock);
virtual bool IsExpiredHasLock() REQUIRES(StatCacheNode::cache_lock);
virtual bool TruncateCacheHasLock() REQUIRES(StatCacheNode::cache_lock);
// For debug
void DumpElementHasLock(const std::string& indent, std::ostringstream& oss) const REQUIRES(StatCacheNode::cache_lock);
virtual void DumpHasLock(const std::string& indent, bool detail, std::ostringstream& oss) REQUIRES(StatCacheNode::cache_lock);
public:
// Properties
static unsigned long GetCacheCount(objtype_t type = objtype_t::UNKNOWN);
static time_t GetExpireTime();
static time_t SetExpireTime(time_t expire, bool is_interval = false);
static time_t UnsetExpireTime();
static bool IsEnableExpireTime();
static bool EnableNegativeCache() { return SetNegativeCache(true); }
static bool DisableNegativeCache() { return SetNegativeCache(false); }
static bool IsEnabledNegativeCache() { return UseNegativeCache; }
static bool PreventExpireCheck();
static bool ResumeExpireCheck();
// Constructor/Destructor
explicit StatCacheNode(const char* path = nullptr, objtype_t type = objtype_t::UNKNOWN);
virtual ~StatCacheNode();
StatCacheNode(const StatCacheNode&) = delete;
StatCacheNode(StatCacheNode&&) = delete;
StatCacheNode& operator=(const StatCacheNode&) = delete;
StatCacheNode& operator=(StatCacheNode&&) = delete;
// Cache Type
bool isSameObjectType(objtype_t type);
bool isDirectory();
bool isFile();
bool isSymlink();
bool isNegative();
// Clear
bool Clear();
bool ClearData();
bool RemoveChild(const std::string& strpath);
// Add
bool Add(const std::string& strpath, const struct stat* pstat, const headers_t* pmeta, objtype_t type, bool is_notruncate = false);
bool AddExtra(const std::string& value);
// Update(Set)
bool Update(const struct stat& stbuf, const headers_t& meta);
bool Update(const struct stat& stbuf, bool clear_meta);
bool Update(bool is_notruncate);
bool Update(const std::string& extvalue);
bool Set(const struct stat& stbuf, const headers_t& meta, bool is_notruncate);
// Get
std::string Get();
bool Get(headers_t* pmeta, struct stat* pstbuf);
bool Get(headers_t& get_meta, struct stat& st);
bool Get(headers_t& get_meta);
bool Get(struct stat& st);
objtype_t GetType() const;
struct timespec GetDate() const;
unsigned long GetHitCount() const;
unsigned long IncrementHitCount();
bool GetExtra(std::string& value);
s3obj_type_map_t::size_type GetChildMap(s3obj_type_map_t& childmap);
// Find
std::shared_ptr<StatCacheNode> Find(const std::string& strpath, const char* petagval = nullptr);
// Cache out
bool IsExpired();
void ClearNoTruncate();
bool TruncateCache();
// For debug
void Dump(bool detail);
};
typedef std::map<std::string, std::shared_ptr<StatCacheNode>> statcache_map_t;
//-------------------------------------------------------------------
// Derived Class : FileStatCache
//-------------------------------------------------------------------
class FileStatCache : public StatCacheNode
{
public:
explicit FileStatCache(const char* path = nullptr);
~FileStatCache() override;
FileStatCache(const FileStatCache&) = delete;
FileStatCache(FileStatCache&&) = delete;
FileStatCache& operator=(const FileStatCache&) = delete;
FileStatCache& operator=(FileStatCache&&) = delete;
};
//-------------------------------------------------------------------
// Derived Class : DirStatCache
//-------------------------------------------------------------------
// [NOTE]
// The fullpath of a DirStatCache always ends with a slash ('/').
// The keys of the 'children' map managed by this object are the partial
// path names of the child objects(files, directories, etc).
// For sub-directory objects, the partial path names do not include a
// slash.
//
class DirStatCache : public StatCacheNode
{
private:
std::mutex dir_cache_lock; // for local variables
struct timespec last_check_date GUARDED_BY(dir_cache_lock) = {0, 0};
objtype_t dir_cache_type GUARDED_BY(dir_cache_lock) = objtype_t::UNKNOWN; // [NOTE] backup for use in destructors only
statcache_map_t children GUARDED_BY(dir_cache_lock);
protected:
bool ClearHasLock() override REQUIRES(StatCacheNode::cache_lock);
bool RemoveChildHasLock(const std::string& strpath) override REQUIRES(StatCacheNode::cache_lock);
bool isRemovableHasLock() override REQUIRES(StatCacheNode::cache_lock);
bool HasExistedChildHasLock() REQUIRES(StatCacheNode::cache_lock, dir_cache_lock);
bool AddHasLock(const std::string& strpath, const struct stat* pstat, const headers_t* pmeta, objtype_t type, bool is_notruncate) override REQUIRES(StatCacheNode::cache_lock);
s3obj_type_map_t::size_type GetChildMapHasLock(s3obj_type_map_t& childmap) override REQUIRES(StatCacheNode::cache_lock);
std::shared_ptr<StatCacheNode> FindHasLock(const std::string& strpath, const char* petagval, bool& needTruncate) override REQUIRES(StatCacheNode::cache_lock);
bool NeedTruncateProcessing();
bool IsExpiredHasLock() override REQUIRES(StatCacheNode::cache_lock);
bool TruncateCacheHasLock() override REQUIRES(StatCacheNode::cache_lock);
bool GetChildLeafNameHasLock(const std::string& strpath, std::string& strLeafName, bool& hasNestedChildren) REQUIRES(StatCacheNode::cache_lock);
void DumpHasLock(const std::string& indent, bool detail, std::ostringstream& oss) override REQUIRES(StatCacheNode::cache_lock);
public:
explicit DirStatCache(const char* path = nullptr, objtype_t type = objtype_t::DIR_NORMAL);
~DirStatCache() override;
DirStatCache(const DirStatCache&) = delete;
DirStatCache(DirStatCache&&) = delete;
DirStatCache& operator=(const DirStatCache&) = delete;
DirStatCache& operator=(DirStatCache&&) = delete;
};
//-------------------------------------------------------------------
// Derived Class : SymlinkStatCache
//-------------------------------------------------------------------
class SymlinkStatCache : public StatCacheNode
{
private:
std::string link_path;
protected:
bool ClearHasLock() override REQUIRES(StatCacheNode::cache_lock);
public:
explicit SymlinkStatCache(const char* path = nullptr);
~SymlinkStatCache() override;
SymlinkStatCache(const SymlinkStatCache&) = delete;
SymlinkStatCache(SymlinkStatCache&&) = delete;
SymlinkStatCache& operator=(const SymlinkStatCache&) = delete;
SymlinkStatCache& operator=(SymlinkStatCache&&) = delete;
};
//-------------------------------------------------------------------
// Derived Class : NegativeStatCache
//-------------------------------------------------------------------
class NegativeStatCache : public StatCacheNode
{
protected:
bool CheckETagValueHasLock(const char* petagval) const override REQUIRES(StatCacheNode::cache_lock);
bool IsExpiredHasLock() override REQUIRES(StatCacheNode::cache_lock);
public:
explicit NegativeStatCache(const char* path = nullptr);
~NegativeStatCache() override;
NegativeStatCache(const NegativeStatCache&) = delete;
NegativeStatCache(NegativeStatCache&&) = delete;
NegativeStatCache& operator=(const NegativeStatCache&) = delete;
NegativeStatCache& operator=(NegativeStatCache&&) = delete;
};
//-------------------------------------------------------------------
// Utility Class : PreventStatCacheExpire
//-------------------------------------------------------------------
class PreventStatCacheExpire
{
public:
explicit PreventStatCacheExpire()
{
StatCacheNode::PreventExpireCheck();
}
~PreventStatCacheExpire()
{
StatCacheNode::ResumeExpireCheck();
}
PreventStatCacheExpire(const PreventStatCacheExpire&) = delete;
PreventStatCacheExpire(PreventStatCacheExpire&&) = delete;
PreventStatCacheExpire& operator=(const PreventStatCacheExpire&) = delete;
PreventStatCacheExpire& operator=(PreventStatCacheExpire&&) = delete;
};
#endif // S3FS_CACHE_NODE_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

View File

@ -1,7 +1,7 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright 2007-2008 Randy Rizun <rrizun@gmail.com>
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -21,128 +21,77 @@
#ifndef S3FS_COMMON_H_
#define S3FS_COMMON_H_
#include <atomic>
#include <string>
#include <sys/types.h>
#include "../config.h"
//
// Macro
//
#define SAFESTRPTR(strptr) (strptr ? strptr : "")
//-------------------------------------------------------------------
// Global variables
//-------------------------------------------------------------------
// TODO: namespace these
static constexpr int64_t FIVE_GB = 5LL * 1024LL * 1024LL * 1024LL;
static constexpr off_t MIN_MULTIPART_SIZE = 5 * 1024 * 1024;
//
// Debug level
//
enum s3fs_log_level{
S3FS_LOG_CRIT = 0, // LOG_CRIT
S3FS_LOG_ERR = 1, // LOG_ERR
S3FS_LOG_WARN = 3, // LOG_WARNING
S3FS_LOG_INFO = 7, // LOG_INFO
S3FS_LOG_DBG = 15 // LOG_DEBUG
};
//
// Debug macros
//
#define IS_S3FS_LOG_CRIT() (S3FS_LOG_CRIT == debug_level)
#define IS_S3FS_LOG_ERR() (S3FS_LOG_ERR == (debug_level & S3FS_LOG_DBG))
#define IS_S3FS_LOG_WARN() (S3FS_LOG_WARN == (debug_level & S3FS_LOG_DBG))
#define IS_S3FS_LOG_INFO() (S3FS_LOG_INFO == (debug_level & S3FS_LOG_DBG))
#define IS_S3FS_LOG_DBG() (S3FS_LOG_DBG == (debug_level & S3FS_LOG_DBG))
#define S3FS_LOG_LEVEL_TO_SYSLOG(level) \
( S3FS_LOG_DBG == (level & S3FS_LOG_DBG) ? LOG_DEBUG : \
S3FS_LOG_INFO == (level & S3FS_LOG_DBG) ? LOG_INFO : \
S3FS_LOG_WARN == (level & S3FS_LOG_DBG) ? LOG_WARNING : \
S3FS_LOG_ERR == (level & S3FS_LOG_DBG) ? LOG_ERR : LOG_CRIT )
#define S3FS_LOG_LEVEL_STRING(level) \
( S3FS_LOG_DBG == (level & S3FS_LOG_DBG) ? "[DBG] " : \
S3FS_LOG_INFO == (level & S3FS_LOG_DBG) ? "[INF] " : \
S3FS_LOG_WARN == (level & S3FS_LOG_DBG) ? "[WAN] " : \
S3FS_LOG_ERR == (level & S3FS_LOG_DBG) ? "[ERR] " : "[CRT] " )
#define S3FS_LOG_NEST_MAX 4
#define S3FS_LOG_NEST(nest) (nest < S3FS_LOG_NEST_MAX ? s3fs_log_nest[nest] : s3fs_log_nest[S3FS_LOG_NEST_MAX - 1])
#define S3FS_LOW_LOGPRN(level, fmt, ...) \
if(S3FS_LOG_CRIT == level || (S3FS_LOG_CRIT != debug_level && level == (debug_level & level))){ \
if(foreground){ \
fprintf(stdout, "%s%s:%s(%d): " fmt "%s\n", S3FS_LOG_LEVEL_STRING(level), __FILE__, __func__, __LINE__, __VA_ARGS__); \
}else{ \
syslog(S3FS_LOG_LEVEL_TO_SYSLOG(level), "%s:%s(%d): " fmt "%s", __FILE__, __func__, __LINE__, __VA_ARGS__); \
} \
}
#define S3FS_LOW_LOGPRN2(level, nest, fmt, ...) \
if(S3FS_LOG_CRIT == level || (S3FS_LOG_CRIT != debug_level && level == (debug_level & level))){ \
if(foreground){ \
fprintf(stdout, "%s%s%s:%s(%d): " fmt "%s\n", S3FS_LOG_LEVEL_STRING(level), S3FS_LOG_NEST(nest), __FILE__, __func__, __LINE__, __VA_ARGS__); \
}else{ \
syslog(S3FS_LOG_LEVEL_TO_SYSLOG(level), "%s" fmt "%s", S3FS_LOG_NEST(nest), __VA_ARGS__); \
} \
}
#define S3FS_LOW_LOGPRN_EXIT(fmt, ...) \
if(foreground){ \
fprintf(stderr, "s3fs: " fmt "%s\n", __VA_ARGS__); \
}else{ \
fprintf(stderr, "s3fs: " fmt "%s\n", __VA_ARGS__); \
syslog(S3FS_LOG_LEVEL_TO_SYSLOG(S3FS_LOG_CRIT), "s3fs: " fmt "%s", __VA_ARGS__); \
}
// [NOTE]
// small trick for VA_ARGS
//
#define S3FS_PRN_EXIT(fmt, ...) S3FS_LOW_LOGPRN_EXIT(fmt, ##__VA_ARGS__, "")
#define S3FS_PRN_CRIT(fmt, ...) S3FS_LOW_LOGPRN(S3FS_LOG_CRIT, fmt, ##__VA_ARGS__, "")
#define S3FS_PRN_ERR(fmt, ...) S3FS_LOW_LOGPRN(S3FS_LOG_ERR, fmt, ##__VA_ARGS__, "")
#define S3FS_PRN_WARN(fmt, ...) S3FS_LOW_LOGPRN(S3FS_LOG_WARN, fmt, ##__VA_ARGS__, "")
#define S3FS_PRN_DBG(fmt, ...) S3FS_LOW_LOGPRN(S3FS_LOG_DBG, fmt, ##__VA_ARGS__, "")
#define S3FS_PRN_INFO(fmt, ...) S3FS_LOW_LOGPRN2(S3FS_LOG_INFO, 0, fmt, ##__VA_ARGS__, "")
#define S3FS_PRN_INFO0(fmt, ...) S3FS_LOG_INFO(fmt, __VA_ARGS__)
#define S3FS_PRN_INFO1(fmt, ...) S3FS_LOW_LOGPRN2(S3FS_LOG_INFO, 1, fmt, ##__VA_ARGS__, "")
#define S3FS_PRN_INFO2(fmt, ...) S3FS_LOW_LOGPRN2(S3FS_LOG_INFO, 2, fmt, ##__VA_ARGS__, "")
#define S3FS_PRN_INFO3(fmt, ...) S3FS_LOW_LOGPRN2(S3FS_LOG_INFO, 3, fmt, ##__VA_ARGS__, "")
#define S3FS_PRN_CURL(fmt, ...) S3FS_LOW_LOGPRN2(S3FS_LOG_CRIT, 0, fmt, ##__VA_ARGS__, "")
//
// Typedef
//
typedef std::map<std::string, std::string> headers_t;
//
// Header "x-amz-meta-xattr" is for extended attributes.
// This header is url encoded string which is json formated.
// x-amz-meta-xattr:urlencod({"xattr-1":"base64(value-1)","xattr-2":"base64(value-2)","xattr-3":"base64(value-3)"})
//
typedef struct xattr_value{
unsigned char* pvalue;
size_t length;
explicit xattr_value(unsigned char* pval = NULL, size_t len = 0) : pvalue(pval), length(len) {}
~xattr_value()
{
if(pvalue){
free(pvalue);
}
}
}XATTRVAL, *PXATTRVAL;
typedef std::map<std::string, PXATTRVAL> xattrs_t;
//
// Global valiables
//
extern bool foreground;
extern bool nomultipart;
extern bool pathrequeststyle;
extern bool complement_stat;
extern bool noxmlns;
extern std::string program_name;
extern std::string service_path;
extern std::string host;
extern std::string bucket;
extern std::string s3host;
extern std::string mount_prefix;
extern std::string endpoint;
extern s3fs_log_level debug_level;
extern const char* s3fs_log_nest[S3FS_LOG_NEST_MAX];
extern std::string region;
extern std::string cipher_suites;
extern std::string instance_name;
extern std::atomic<long long unsigned> num_requests_head_object;
extern std::atomic<long long unsigned> num_requests_put_object;
extern std::atomic<long long unsigned> num_requests_get_object;
extern std::atomic<long long unsigned> num_requests_delete_object;
extern std::atomic<long long unsigned> num_requests_list_bucket;
extern std::atomic<long long unsigned> num_requests_mpu_initiate;
extern std::atomic<long long unsigned> num_requests_mpu_complete;
extern std::atomic<long long unsigned> num_requests_mpu_abort;
extern std::atomic<long long unsigned> num_requests_mpu_upload_part;
extern std::atomic<long long unsigned> num_requests_mpu_copy_part;
//-------------------------------------------------------------------
// For weak attribute
//-------------------------------------------------------------------
#define S3FS_FUNCATTR_WEAK __attribute__ ((weak,unused))
//-------------------------------------------------------------------
// For clang -Wthread-safety
//-------------------------------------------------------------------
#ifdef __clang__
#define THREAD_ANNOTATION_ATTRIBUTE(x) __attribute__((x))
#else
#define THREAD_ANNOTATION_ATTRIBUTE(x) // no-op
#endif
#define GUARDED_BY(x) \
THREAD_ANNOTATION_ATTRIBUTE(guarded_by(x))
#define PT_GUARDED_BY(x) \
THREAD_ANNOTATION_ATTRIBUTE(pt_guarded_by(x))
#define REQUIRES(...) \
THREAD_ANNOTATION_ATTRIBUTE(requires_capability(__VA_ARGS__))
#define RETURN_CAPABILITY(...) \
THREAD_ANNOTATION_ATTRIBUTE(lock_returned(__VA_ARGS__))
#define ACQUIRED_BEFORE(...) \
THREAD_ANNOTATION_ATTRIBUTE(acquired_before(__VA_ARGS__))
#define ACQUIRED_AFTER(...) \
THREAD_ANNOTATION_ATTRIBUTE(acquired_after(__VA_ARGS__))
#define NO_THREAD_SAFETY_ANALYSIS \
THREAD_ANNOTATION_ATTRIBUTE(no_thread_safety_analysis)
#endif // S3FS_COMMON_H_
@ -151,6 +100,6 @@ extern const char* s3fs_log_nest[S3FS_LOG_NEST_MAX];
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

View File

@ -1,7 +1,7 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright 2007-2008 Randy Rizun <rrizun@gmail.com>
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -18,74 +18,37 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#include <string>
#include "s3fs_auth.h"
#include "string_util.h"
using namespace std;
//-------------------------------------------------------------------
// Utility Function
//-------------------------------------------------------------------
string s3fs_get_content_md5(int fd)
std::string s3fs_get_content_md5(int fd)
{
unsigned char* md5hex;
char* base64;
string Signature;
if(NULL == (md5hex = s3fs_md5hexsum(fd, 0, -1))){
return string("");
}
if(NULL == (base64 = s3fs_base64(md5hex, get_md5_digest_length()))){
return string(""); // ENOMEM
}
free(md5hex);
Signature = base64;
free(base64);
return Signature;
md5_t md5;
if(!s3fs_md5_fd(fd, 0, -1, &md5)){
// TODO: better return value?
return "";
}
return s3fs_base64(md5.data(), md5.size());
}
string s3fs_md5sum(int fd, off_t start, ssize_t size)
std::string s3fs_sha256_hex_fd(int fd, off_t start, off_t size)
{
size_t digestlen = get_md5_digest_length();
unsigned char* md5hex;
sha256_t sha256;
if(NULL == (md5hex = s3fs_md5hexsum(fd, start, size))){
return string("");
}
if(!s3fs_sha256_fd(fd, start, size, &sha256)){
// TODO: better return value?
return "";
}
std::string md5 = s3fs_hex(md5hex, digestlen);
free(md5hex);
std::string sha256hex = s3fs_hex_lower(sha256.data(), sha256.size());
return md5;
}
string s3fs_sha256sum(int fd, off_t start, ssize_t size)
{
size_t digestlen = get_sha256_digest_length();
char sha256[2 * digestlen + 1];
char hexbuf[3];
unsigned char* sha256hex;
if(NULL == (sha256hex = s3fs_sha256hexsum(fd, start, size))){
return string("");
}
memset(sha256, 0, 2 * digestlen + 1);
for(size_t pos = 0; pos < digestlen; pos++){
snprintf(hexbuf, 3, "%02x", sha256hex[pos]);
strncat(sha256, hexbuf, 2);
}
free(sha256hex);
return string(sha256);
return sha256hex;
}
/*
@ -93,6 +56,6 @@ string s3fs_sha256sum(int fd, off_t start, ssize_t size)
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright 2007-2008 Randy Rizun <rrizun@gmail.com>
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -21,466 +21,347 @@
#ifndef S3FS_CURL_H_
#define S3FS_CURL_H_
#include <cassert>
#include <atomic>
#include <cstdint>
#include <curl/curl.h>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
#include "common.h"
#include "fdcache_page.h"
#include "metaheader.h"
#include "s3fs_util.h"
#include "types.h"
//----------------------------------------------
// Symbols
// Avoid dependency on libcurl version
//----------------------------------------------
#define MIN_MULTIPART_SIZE 5242880 // 5MB
//----------------------------------------------
// class BodyData
//----------------------------------------------
// memory class for curl write memory callback
// [NOTE]
// The following symbols (enum) depend on the version of libcurl.
// CURLOPT_TCP_KEEPALIVE 7.25.0 and later
// CURLOPT_SSL_ENABLE_ALPN 7.36.0 and later
// CURLOPT_KEEP_SENDING_ON_ERROR 7.51.0 and later
//
class BodyData
{
private:
char* text;
size_t lastpos;
size_t bufsize;
// s3fs uses these, if you build s3fs with the old libcurl,
// substitute the following symbols to avoid errors.
// If the version of libcurl linked at runtime is old,
// curl_easy_setopt results in an error(CURLE_UNKNOWN_OPTION) and
// a message is output.
//
#if defined(HAVE_CURLOPT_TCP_KEEPALIVE) && (HAVE_CURLOPT_TCP_KEEPALIVE == 1)
#define S3FS_CURLOPT_TCP_KEEPALIVE CURLOPT_TCP_KEEPALIVE
#else
#define S3FS_CURLOPT_TCP_KEEPALIVE static_cast<CURLoption>(213)
#endif
private:
bool IsSafeSize(size_t addbytes) const {
return ((lastpos + addbytes + 1) > bufsize ? false : true);
}
bool Resize(size_t addbytes);
#if defined(HAVE_CURLOPT_SSL_ENABLE_ALPN) && (HAVE_CURLOPT_SSL_ENABLE_ALPN == 1)
#define S3FS_CURLOPT_SSL_ENABLE_ALPN CURLOPT_SSL_ENABLE_ALPN
#else
#define S3FS_CURLOPT_SSL_ENABLE_ALPN static_cast<CURLoption>(226)
#endif
public:
BodyData() : text(NULL), lastpos(0), bufsize(0) {}
~BodyData() {
Clear();
}
void Clear(void);
bool Append(void* ptr, size_t bytes);
bool Append(void* ptr, size_t blockSize, size_t numBlocks) {
return Append(ptr, (blockSize * numBlocks));
}
const char* str() const;
size_t size() const {
return lastpos;
}
};
#if defined(HAVE_CURLOPT_KEEP_SENDING_ON_ERROR) && (HAVE_CURLOPT_KEEP_SENDING_ON_ERROR == 1)
#define S3FS_CURLOPT_KEEP_SENDING_ON_ERROR CURLOPT_KEEP_SENDING_ON_ERROR
#else
#define S3FS_CURLOPT_KEEP_SENDING_ON_ERROR static_cast<CURLoption>(245)
#endif
//----------------------------------------------
// Utility structs & typedefs
// Structure / Typedefs
//----------------------------------------------
typedef std::vector<std::string> etaglist_t;
// Each part information for Multipart upload
struct filepart
{
bool uploaded; // does finish uploading
std::string etag; // expected etag value
int fd; // base file(temporary full file) descriptor
off_t startpos; // seek fd point for uploading
ssize_t size; // uploading size
etaglist_t* etaglist; // use only parallel upload
int etagpos; // use only parallel upload
filepart() : uploaded(false), fd(-1), startpos(0), size(-1), etaglist(NULL), etagpos(-1) {}
~filepart()
{
clear();
}
void clear(void)
{
uploaded = false;
etag = "";
fd = -1;
startpos = 0;
size = -1;
etaglist = NULL;
etagpos = - 1;
}
void add_etag_list(etaglist_t* list)
{
if(list){
list->push_back(std::string(""));
etaglist = list;
etagpos = list->size() - 1;
}else{
etaglist = NULL;
etagpos = - 1;
}
}
};
// for progress
struct case_insensitive_compare_func
{
bool operator()(const std::string& a, const std::string& b) const {
return strcasecmp(a.c_str(), b.c_str()) < 0;
}
};
typedef std::map<std::string, std::string, case_insensitive_compare_func> mimes_t;
typedef std::pair<double, double> progress_t;
typedef std::map<CURL*, time_t> curltime_t;
typedef std::map<CURL*, progress_t> curlprogress_t;
class S3fsMultiCurl;
//----------------------------------------------
// class CurlHandlerPool
//----------------------------------------------
class CurlHandlerPool
{
public:
CurlHandlerPool(int maxHandlers)
: mMaxHandlers(maxHandlers)
, mHandlers(NULL)
, mIndex(-1)
{
assert(maxHandlers > 0);
}
bool Init();
bool Destroy();
CURL* GetHandler();
void ReturnHandler(CURL* h);
private:
int mMaxHandlers;
pthread_mutex_t mLock;
CURL** mHandlers;
int mIndex;
struct curlprogress {
time_t time;
double dl_progress;
double ul_progress;
};
typedef std::unique_ptr<CURL, decltype(&curl_easy_cleanup)> CurlUniquePtr;
//----------------------------------------------
// class S3fsCurl
//----------------------------------------------
typedef std::map<std::string, std::string> iamcredmap_t;
class S3fsCred;
class S3fsCurl;
// Prototype function for lazy setup options for curl handle
typedef bool (*s3fscurl_lazy_setup)(S3fsCurl* s3fscurl);
typedef std::map<std::string, std::string> sseckeymap_t;
typedef std::list<sseckeymap_t> sseckeylist_t;
// strage class(rrs)
enum storage_class_t {
STANDARD,
STANDARD_IA,
REDUCED_REDUNDANCY
};
// sse type
enum sse_type_t {
SSE_DISABLE = 0, // not use server side encrypting
SSE_S3, // server side encrypting by S3 key
SSE_C, // server side encrypting by custom key
SSE_KMS // server side encrypting by kms id
};
// share
#define SHARE_MUTEX_DNS 0
#define SHARE_MUTEX_SSL_SESSION 1
#define SHARE_MUTEX_MAX 2
typedef std::vector<sseckeymap_t> sseckeylist_t;
// Class for lapping curl
//
class S3fsCurl
{
friend class S3fsMultiCurl;
private:
enum class REQTYPE : int8_t {
UNSET = -1,
DELETE,
HEAD,
PUTHEAD,
PUT,
GET,
CHKBUCKET,
LISTBUCKET,
PREMULTIPOST,
COMPLETEMULTIPOST,
UPLOADMULTIPOST,
COPYMULTIPOST,
MULTILIST,
IAMCRED,
ABORTMULTIUPLOAD,
IAMROLE
};
private:
enum REQTYPE {
REQTYPE_UNSET = -1,
REQTYPE_DELETE = 0,
REQTYPE_HEAD,
REQTYPE_PUTHEAD,
REQTYPE_PUT,
REQTYPE_GET,
REQTYPE_CHKBUCKET,
REQTYPE_LISTBUCKET,
REQTYPE_PREMULTIPOST,
REQTYPE_COMPLETEMULTIPOST,
REQTYPE_UPLOADMULTIPOST,
REQTYPE_COPYMULTIPOST,
REQTYPE_MULTILIST,
REQTYPE_IAMCRED,
REQTYPE_ABORTMULTIUPLOAD,
REQTYPE_IAMROLE
};
// Environment name
static constexpr char S3FS_SSL_PRIVKEY_PASSWORD[] = "S3FS_SSL_PRIVKEY_PASSWORD";
// class variables
static pthread_mutex_t curl_handles_lock;
static pthread_mutex_t curl_share_lock[SHARE_MUTEX_MAX];
static bool is_initglobal_done;
static CurlHandlerPool* sCurlPool;
static int sCurlPoolSize;
static CURLSH* hCurlShare;
static bool is_cert_check;
static bool is_dns_cache;
static bool is_ssl_session_cache;
static long connect_timeout;
static time_t readwrite_timeout;
static int retries;
static bool is_public_bucket;
static std::string default_acl; // TODO: to enum
static storage_class_t storage_class;
static sseckeylist_t sseckeys;
static std::string ssekmsid;
static sse_type_t ssetype;
static bool is_content_md5;
static bool is_verbose;
static std::string AWSAccessKeyId;
static std::string AWSSecretAccessKey;
static std::string AWSAccessToken;
static time_t AWSAccessTokenExpire;
static std::string IAM_role;
static long ssl_verify_hostname;
static curltime_t curl_times;
static curlprogress_t curl_progress;
static std::string curl_ca_bundle;
static mimes_t mimeTypes;
static int max_parallel_cnt;
static off_t multipart_size;
static bool is_sigv4;
static bool is_ua; // User-Agent
// class variables
static std::atomic<bool> curl_warnings_once; // emit older curl warnings only once
static std::mutex curl_handles_lock;
static struct callback_locks_t {
std::mutex dns;
std::mutex ssl_session;
} callback_locks;
static bool is_initglobal_done;
static bool is_cert_check;
static long connect_timeout;
static time_t readwrite_timeout;
static int retries;
static bool is_public_bucket;
static acl_t default_acl;
static std::string storage_class;
static sseckeylist_t sseckeys;
static std::string ssekmsid;
static sse_type_t ssetype;
static bool is_content_md5;
static bool is_verbose;
static bool is_dump_body;
static S3fsCred* ps3fscred;
static long ssl_verify_hostname;
static std::string client_cert;
static std::string client_cert_type;
static std::string client_priv_key;
static std::string client_priv_key_type;
static std::string client_key_password;
static std::map<const CURL*, curlprogress> curl_progress;
static std::string curl_ca_bundle;
static mimes_t mimeTypes;
static std::string userAgent;
static int max_multireq;
static off_t multipart_size;
static off_t multipart_copy_size;
static signature_type_t signature_type;
static bool is_unsigned_payload;
static bool is_ua; // User-Agent
static bool listobjectsv2;
static bool requester_pays;
static std::string proxy_url;
static bool proxy_http;
static std::string proxy_userpwd; // load from file(<username>:<passphrase>)
static long ipresolve_type; // this value is a libcurl symbol.
// variables
CURL* hCurl;
REQTYPE type; // type of request
std::string path; // target object path
std::string base_path; // base path (for multi curl head request)
std::string saved_path; // saved path = cache key (for multi curl head request)
std::string url; // target object path(url)
struct curl_slist* requestHeaders;
headers_t responseHeaders; // header data by HeaderCallback
BodyData* bodydata; // body data by WriteMemoryCallback
BodyData* headdata; // header data by WriteMemoryCallback
long LastResponseCode;
const unsigned char* postdata; // use by post method and read callback function.
int postdata_remaining; // use by post method and read callback function.
filepart partdata; // use by multipart upload/get object callback
bool is_use_ahbe; // additional header by extension
int retry_count; // retry count for multipart
FILE* b_infile; // backup for retrying
const unsigned char* b_postdata; // backup for retrying
int b_postdata_remaining; // backup for retrying
off_t b_partdata_startpos; // backup for retrying
ssize_t b_partdata_size; // backup for retrying
int b_ssekey_pos; // backup for retrying
std::string b_ssevalue; // backup for retrying
sse_type_t b_ssetype; // backup for retrying
// variables
CurlUniquePtr hCurl PT_GUARDED_BY(curl_handles_lock) = {nullptr, curl_easy_cleanup};
REQTYPE type; // type of request
std::string path; // target object path
std::string url; // target object path(url)
struct curl_slist* requestHeaders;
headers_t responseHeaders; // header data by HeaderCallback
std::string bodydata; // body data by WriteMemoryCallback
std::string headdata; // header data by WriteMemoryCallback
long LastResponseCode;
const unsigned char* postdata; // use by post method and read callback function.
off_t postdata_remaining; // use by post method and read callback function.
filepart partdata; // use by multipart upload/get object callback
bool is_use_ahbe; // additional header by extension
int retry_count; // retry count, this is used only sleep time before retrying
std::unique_ptr<FILE, decltype(&s3fs_fclose)> b_infile = {nullptr, &s3fs_fclose}; // backup for retrying
const unsigned char* b_postdata; // backup for retrying
off_t b_postdata_remaining; // backup for retrying
off_t b_partdata_startpos; // backup for retrying
off_t b_partdata_size; // backup for retrying
std::string op; // the HTTP verb of the request ("PUT", "GET", etc.)
std::string query_string; // request query string
s3fscurl_lazy_setup fpLazySetup; // curl options for lazy setting function
CURLcode curlCode; // handle curl return
public:
// constructor/destructor
explicit S3fsCurl(bool ahbe = false);
~S3fsCurl();
public:
static constexpr long S3FSCURL_RESPONSECODE_NOTSET = -1;
static constexpr long S3FSCURL_RESPONSECODE_FATAL_ERROR = -2;
static constexpr int S3FSCURL_PERFORM_RESULT_NOTSET = 1;
private:
// class methods
static bool InitGlobalCurl(void);
static bool DestroyGlobalCurl(void);
static bool InitShareCurl(void);
static bool DestroyShareCurl(void);
static void LockCurlShare(CURL* handle, curl_lock_data nLockData, curl_lock_access laccess, void* useptr);
static void UnlockCurlShare(CURL* handle, curl_lock_data nLockData, void* useptr);
static bool InitCryptMutex(void);
static bool DestroyCryptMutex(void);
static int CurlProgress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
public:
// constructor/destructor
explicit S3fsCurl(bool ahbe = false);
~S3fsCurl();
S3fsCurl(const S3fsCurl&) = delete;
S3fsCurl(S3fsCurl&&) = delete;
S3fsCurl& operator=(const S3fsCurl&) = delete;
S3fsCurl& operator=(S3fsCurl&&) = delete;
static bool InitMimeType(const char* MimeFile = NULL);
static bool LocateBundle(void);
static size_t HeaderCallback(void *data, size_t blockSize, size_t numBlocks, void *userPtr);
static size_t WriteMemoryCallback(void *ptr, size_t blockSize, size_t numBlocks, void *data);
static size_t ReadCallback(void *ptr, size_t size, size_t nmemb, void *userp);
static size_t UploadReadCallback(void *ptr, size_t size, size_t nmemb, void *userp);
static size_t DownloadWriteCallback(void* ptr, size_t size, size_t nmemb, void* userp);
private:
// class methods
static bool InitGlobalCurl();
static bool DestroyGlobalCurl();
static bool InitCryptMutex();
static bool DestroyCryptMutex();
static int CurlProgress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
static std::string extractURI(const std::string& url);
static bool UploadMultipartPostCallback(S3fsCurl* s3fscurl);
static S3fsCurl* UploadMultipartPostRetryCallback(S3fsCurl* s3fscurl);
static S3fsCurl* ParallelGetObjectRetryCallback(S3fsCurl* s3fscurl);
static bool LocateBundle();
static size_t HeaderCallback(void *data, size_t blockSize, size_t numBlocks, void *userPtr);
static size_t WriteMemoryCallback(void *ptr, size_t blockSize, size_t numBlocks, void *data);
static size_t ReadCallback(void *ptr, size_t size, size_t nmemb, void *userp);
static size_t UploadReadCallback(void *ptr, size_t size, size_t nmemb, void *userp);
static size_t DownloadWriteCallback(void* ptr, size_t size, size_t nmemb, void* userp);
static bool ParseIAMCredentialResponse(const char* response, iamcredmap_t& keyval);
static bool SetIAMCredentials(const char* response);
static bool ParseIAMRoleFromMetaDataResponse(const char* response, std::string& rolename);
static bool SetIAMRoleFromMetaData(const char* response);
static bool LoadEnvSseCKeys(void);
static bool LoadEnvSseKmsid(void);
static bool PushbackSseKeys(std::string& onekey);
static bool AddUserAgent(CURL* hCurl);
// lazy functions for set curl options
static bool MultipartUploadPartSetCurlOpts(S3fsCurl* s3fscurl);
static bool CopyMultipartUploadSetCurlOpts(S3fsCurl* s3fscurl);
static bool PreGetObjectRequestSetCurlOpts(S3fsCurl* s3fscurl);
static bool PreHeadRequestSetCurlOpts(S3fsCurl* s3fscurl);
static int CurlDebugFunc(CURL* hcurl, curl_infotype type, char* data, size_t size, void* userptr);
static bool LoadEnvSseCKeys();
static bool LoadEnvSseKmsid();
static bool PushbackSseKeys(const std::string& onekey);
static bool AddUserAgent(const CurlUniquePtr& hCurl);
// methods
bool ResetHandle(void);
bool RemakeHandle(void);
bool ClearInternalData(void);
void insertV4Headers(const std::string &op, const std::string &path, const std::string &query_string, const std::string &payload_hash);
std::string CalcSignatureV2(const std::string& method, const std::string& strMD5, const std::string& content_type, const std::string& date, const std::string& resource);
std::string CalcSignature(const std::string& method, const std::string& canonical_uri, const std::string& query_string, const std::string& strdate, const std::string& payload_hash, const std::string& date8601);
bool GetUploadId(std::string& upload_id);
int GetIAMCredentials(void);
static int CurlDebugFunc(const CURL* hcurl, curl_infotype type, char* data, size_t size, void* userptr);
static int CurlDebugBodyInFunc(const CURL* hcurl, curl_infotype type, char* data, size_t size, void* userptr);
static int CurlDebugBodyOutFunc(const CURL* hcurl, curl_infotype type, char* data, size_t size, void* userptr);
static int RawCurlDebugFunc(const CURL* hcurl, curl_infotype type, char* data, size_t size, void* userptr, curl_infotype datatype);
int UploadMultipartPostSetup(const char* tpath, int part_num, const std::string& upload_id);
int CopyMultipartPostRequest(const char* from, const char* to, int part_num, std::string& upload_id, headers_t& meta);
// methods
bool ResetHandle() REQUIRES(S3fsCurl::curl_handles_lock);
bool RemakeHandle();
bool ClearInternalData();
bool insertV4Headers(const std::string& access_key_id, const std::string& secret_access_key, const std::string& access_token);
void insertV2Headers(const std::string& access_key_id, const std::string& secret_access_key, const std::string& access_token);
void insertIBMIAMHeaders(const std::string& access_key_id, const std::string& access_token);
bool insertAuthHeaders();
bool AddSseRequestHead(sse_type_t ssetype, const std::string& ssevalue, bool is_copy);
bool PreHeadRequest(const char* tpath, size_t ssekey_pos = -1);
bool PreHeadRequest(const std::string& tpath, size_t ssekey_pos = -1) {
return PreHeadRequest(tpath.c_str(), ssekey_pos);
}
std::string CalcSignatureV2(const std::string& method, const std::string& strMD5, const std::string& content_type, const std::string& date, const std::string& resource, const std::string& secret_access_key, const std::string& access_token);
std::string CalcSignature(const std::string& method, const std::string& canonical_uri, const std::string& query_string, const std::string& strdate, const std::string& payload_hash, const std::string& date8601, const std::string& secret_access_key, const std::string& access_token);
int MultipartUploadContentPartSetup(const char* tpath, int part_num, const std::string& upload_id);
int MultipartUploadCopyPartSetup(const char* from, const char* to, int part_num, const std::string& upload_id, const headers_t& meta);
bool MultipartUploadContentPartComplete();
bool MultipartUploadCopyPartComplete();
int MapPutErrorResponse(int result) const;
public:
// class methods
static bool InitS3fsCurl(const char* MimeFile = NULL);
static bool DestroyS3fsCurl(void);
static int ParallelMultipartUploadRequest(const char* tpath, headers_t& meta, int fd);
static int ParallelGetObjectRequest(const char* tpath, int fd, off_t start, ssize_t size);
static bool CheckIAMCredentialUpdate(void);
public:
// class methods
static bool InitS3fsCurl();
static bool InitCredentialObject(S3fsCred* pcredobj);
static bool InitMimeType(const std::string& strFile);
static bool DestroyS3fsCurl();
// class methods(valiables)
static std::string LookupMimeType(const std::string& name);
static bool SetCheckCertificate(bool isCertCheck);
static bool SetDnsCache(bool isCache);
static bool SetSslSessionCache(bool isCache);
static long SetConnectTimeout(long timeout);
static time_t SetReadwriteTimeout(time_t timeout);
static time_t GetReadwriteTimeout(void) { return S3fsCurl::readwrite_timeout; }
static int SetRetries(int count);
static bool SetPublicBucket(bool flag);
static bool IsPublicBucket(void) { return S3fsCurl::is_public_bucket; }
static std::string SetDefaultAcl(const char* acl);
static storage_class_t SetStorageClass(storage_class_t storage_class);
static storage_class_t GetStorageClass() { return S3fsCurl::storage_class; }
static bool LoadEnvSse(void) { return (S3fsCurl::LoadEnvSseCKeys() && S3fsCurl::LoadEnvSseKmsid()); }
static sse_type_t SetSseType(sse_type_t type);
static sse_type_t GetSseType(void) { return S3fsCurl::ssetype; }
static bool IsSseDisable(void) { return (SSE_DISABLE == S3fsCurl::ssetype); }
static bool IsSseS3Type(void) { return (SSE_S3 == S3fsCurl::ssetype); }
static bool IsSseCType(void) { return (SSE_C == S3fsCurl::ssetype); }
static bool IsSseKmsType(void) { return (SSE_KMS == S3fsCurl::ssetype); }
static bool FinalCheckSse(void);
static bool SetSseCKeys(const char* filepath);
static bool SetSseKmsid(const char* kmsid);
static bool IsSetSseKmsId(void) { return !S3fsCurl::ssekmsid.empty(); }
static const char* GetSseKmsId(void) { return S3fsCurl::ssekmsid.c_str(); }
static bool GetSseKey(std::string& md5, std::string& ssekey);
static bool GetSseKeyMd5(int pos, std::string& md5);
static int GetSseKeyCount(void);
static bool SetContentMd5(bool flag);
static bool SetVerbose(bool flag);
static bool GetVerbose(void) { return S3fsCurl::is_verbose; }
static bool SetAccessKey(const char* AccessKeyId, const char* SecretAccessKey);
static bool IsSetAccessKeyId(void){
return (0 < S3fsCurl::IAM_role.size() || (0 < S3fsCurl::AWSAccessKeyId.size() && 0 < S3fsCurl::AWSSecretAccessKey.size()));
}
static long SetSslVerifyHostname(long value);
static long GetSslVerifyHostname(void) { return S3fsCurl::ssl_verify_hostname; }
static int SetMaxParallelCount(int value);
static int GetMaxParallelCount(void) { return S3fsCurl::max_parallel_cnt; }
static std::string SetIAMRole(const char* role);
static const char* GetIAMRole(void) { return S3fsCurl::IAM_role.c_str(); }
static bool SetMultipartSize(off_t size);
static off_t GetMultipartSize(void) { return S3fsCurl::multipart_size; }
static bool SetSignatureV4(bool isset) { bool bresult = S3fsCurl::is_sigv4; S3fsCurl::is_sigv4 = isset; return bresult; }
static bool IsSignatureV4(void) { return S3fsCurl::is_sigv4; }
static bool SetUserAgentFlag(bool isset) { bool bresult = S3fsCurl::is_ua; S3fsCurl::is_ua = isset; return bresult; }
static bool IsUserAgentFlag(void) { return S3fsCurl::is_ua; }
// class methods(variables)
static std::string LookupMimeType(const std::string& name);
static bool SetCheckCertificate(bool isCertCheck);
static long SetConnectTimeout(long timeout);
static time_t SetReadwriteTimeout(time_t timeout);
static time_t GetReadwriteTimeout() { return S3fsCurl::readwrite_timeout; }
static int SetRetries(int count);
static int GetRetries();
static bool SetPublicBucket(bool flag);
static bool IsPublicBucket() { return S3fsCurl::is_public_bucket; }
static acl_t SetDefaultAcl(acl_t acl);
static acl_t GetDefaultAcl();
static std::string SetStorageClass(const std::string& storage_class);
static std::string GetStorageClass() { return S3fsCurl::storage_class; }
static bool LoadEnvSse() { return (S3fsCurl::LoadEnvSseCKeys() && S3fsCurl::LoadEnvSseKmsid()); }
static sse_type_t SetSseType(sse_type_t type);
static sse_type_t GetSseType() { return S3fsCurl::ssetype; }
static bool IsSseDisable() { return (sse_type_t::SSE_DISABLE == S3fsCurl::ssetype); }
static bool IsSseS3Type() { return (sse_type_t::SSE_S3 == S3fsCurl::ssetype); }
static bool IsSseCType() { return (sse_type_t::SSE_C == S3fsCurl::ssetype); }
static bool IsSseKmsType() { return (sse_type_t::SSE_KMS == S3fsCurl::ssetype); }
static bool FinalCheckSse();
static bool SetSseCKeys(const char* filepath);
static bool SetSseKmsid(const char* kmsid);
static bool IsSetSseKmsId() { return !S3fsCurl::ssekmsid.empty(); }
static const char* GetSseKmsId() { return S3fsCurl::ssekmsid.c_str(); }
static bool GetSseKey(std::string& md5, std::string& ssekey);
static bool GetSseKeyMd5(size_t pos, std::string& md5);
static size_t GetSseKeyCount();
static bool SetContentMd5(bool flag);
static bool SetVerbose(bool flag);
static bool GetVerbose() { return S3fsCurl::is_verbose; }
static bool SetDumpBody(bool flag);
static bool IsDumpBody() { return S3fsCurl::is_dump_body; }
static long SetSslVerifyHostname(long value);
static long GetSslVerifyHostname() { return S3fsCurl::ssl_verify_hostname; }
static bool SetSSLClientCertOptions(const std::string& values);
static void ResetOffset(S3fsCurl* pCurl);
static bool SetMultipartSize(off_t size);
static off_t GetMultipartSize() { return S3fsCurl::multipart_size; }
static bool SetMultipartCopySize(off_t size);
static off_t GetMultipartCopySize() { return S3fsCurl::multipart_copy_size; }
static signature_type_t SetSignatureType(signature_type_t signature_type) { signature_type_t bresult = S3fsCurl::signature_type; S3fsCurl::signature_type = signature_type; return bresult; }
static signature_type_t GetSignatureType() { return S3fsCurl::signature_type; }
static bool SetUnsignedPayload(bool issset) { bool bresult = S3fsCurl::is_unsigned_payload; S3fsCurl::is_unsigned_payload = issset; return bresult; }
static bool GetUnsignedPayload() { return S3fsCurl::is_unsigned_payload; }
static bool SetUserAgentFlag(bool isset) { bool bresult = S3fsCurl::is_ua; S3fsCurl::is_ua = isset; return bresult; }
static bool IsUserAgentFlag() { return S3fsCurl::is_ua; }
static void InitUserAgent();
static bool SetListObjectsV2(bool isset) { bool bresult = S3fsCurl::listobjectsv2; S3fsCurl::listobjectsv2 = isset; return bresult; }
static bool IsListObjectsV2() { return S3fsCurl::listobjectsv2; }
static bool SetRequesterPays(bool flag) { bool old_flag = S3fsCurl::requester_pays; S3fsCurl::requester_pays = flag; return old_flag; }
static bool IsRequesterPays() { return S3fsCurl::requester_pays; }
static bool SetProxy(const char* url);
static bool SetProxyUserPwd(const char* userpwd);
static bool SetIPResolveType(const char* value);
// methods
bool CreateCurlHandle(bool force = false);
bool DestroyCurlHandle(void);
// methods
bool CreateCurlHandle(bool remake = false);
bool DestroyCurlHandle(bool clear_internal_data = true);
bool DestroyCurlHandleHasLock(bool clear_internal_data = true) REQUIRES(S3fsCurl::curl_handles_lock);
bool LoadIAMRoleFromMetaData(void);
bool AddSseRequestHead(sse_type_t ssetype, std::string& ssevalue, bool is_only_c, bool is_copy);
bool GetResponseCode(long& responseCode);
int RequestPerform(void);
int DeleteRequest(const char* tpath);
bool PreHeadRequest(const char* tpath, const char* bpath = NULL, const char* savedpath = NULL, int ssekey_pos = -1);
bool PreHeadRequest(std::string& tpath, std::string& bpath, std::string& savedpath, int ssekey_pos = -1) {
return PreHeadRequest(tpath.c_str(), bpath.c_str(), savedpath.c_str(), ssekey_pos);
}
int HeadRequest(const char* tpath, headers_t& meta);
int PutHeadRequest(const char* tpath, headers_t& meta, bool is_copy);
int PutRequest(const char* tpath, headers_t& meta, int fd);
int PreGetObjectRequest(const char* tpath, int fd, off_t start, ssize_t size, sse_type_t ssetype, std::string& ssevalue);
int GetObjectRequest(const char* tpath, int fd, off_t start = -1, ssize_t size = -1);
int CheckBucket(void);
int ListBucketRequest(const char* tpath, const char* query);
int PreMultipartPostRequest(const char* tpath, headers_t& meta, std::string& upload_id, bool is_copy);
int CompleteMultipartPostRequest(const char* tpath, std::string& upload_id, etaglist_t& parts);
int UploadMultipartPostRequest(const char* tpath, int part_num, const std::string& upload_id);
int MultipartListRequest(std::string& body);
int AbortMultipartUpload(const char* tpath, std::string& upload_id);
int MultipartHeadRequest(const char* tpath, off_t size, headers_t& meta, bool is_copy);
int MultipartUploadRequest(const char* tpath, headers_t& meta, int fd, bool is_copy);
int MultipartUploadRequest(const std::string& upload_id, const char* tpath, int fd, off_t offset, size_t size, etaglist_t& list);
int MultipartRenameRequest(const char* from, const char* to, headers_t& meta, off_t size);
bool GetIAMCredentials(const char* cred_url, const char* iam_v2_token, const char* ibm_secret_access_key, std::string& response);
bool GetIAMRoleFromMetaData(const char* cred_url, const char* iam_v2_token, std::string& token);
bool GetResponseCode(long& responseCode, bool from_curl_handle = true) const;
int RequestPerform(bool dontAddAuthHeaders=false);
int DeleteRequest(const char* tpath);
int GetIAMv2ApiToken(const char* token_url, int token_ttl, const char* token_ttl_hdr, std::string& response);
int HeadRequest(const char* tpath, headers_t& meta);
int PutHeadRequest(const char* tpath, const headers_t& meta, bool is_copy);
int PutRequest(const char* tpath, headers_t& meta, int fd);
int PreGetObjectRequest(const char* tpath, int fd, off_t start, off_t size, sse_type_t ssetype, const std::string& ssevalue);
int GetObjectRequest(const char* tpath, int fd, off_t start, off_t size, sse_type_t ssetype, const std::string& ssevalue);
int CheckBucket(const char* check_path, bool compat_dir, bool force_no_sse);
int ListBucketRequest(const char* tpath, const char* query);
int PreMultipartUploadRequest(const char* tpath, const headers_t& meta, std::string& upload_id);
int MultipartUploadPartSetup(const char* tpath, int upload_fd, off_t start, off_t size, int part_num, const std::string& upload_id, etagpair* petag, bool is_copy);
int MultipartUploadComplete(const char* tpath, const std::string& upload_id, const etaglist_t& parts);
bool MultipartUploadPartComplete();
int MultipartListRequest(std::string& body);
int AbortMultipartUpload(const char* tpath, const std::string& upload_id);
int MultipartPutHeadRequest(const std::string& from, const std::string& to, int part_number, const std::string& upload_id, const headers_t& meta);
int MultipartUploadPartRequest(const char* tpath, int upload_fd, off_t start, off_t size, int part_num, const std::string& upload_id, etagpair* petag, bool is_copy);
// methods(valiables)
CURL* GetCurlHandle(void) const { return hCurl; }
std::string GetPath(void) const { return path; }
std::string GetBasePath(void) const { return base_path; }
std::string GetSpacialSavedPath(void) const { return saved_path; }
std::string GetUrl(void) const { return url; }
headers_t* GetResponseHeaders(void) { return &responseHeaders; }
BodyData* GetBodyData(void) const { return bodydata; }
BodyData* GetHeadData(void) const { return headdata; }
long GetLastResponseCode(void) const { return LastResponseCode; }
bool SetUseAhbe(bool ahbe);
bool EnableUseAhbe(void) { return SetUseAhbe(true); }
bool DisableUseAhbe(void) { return SetUseAhbe(false); }
bool IsUseAhbe(void) const { return is_use_ahbe; }
int GetMultipartRetryCount(void) const { return retry_count; }
void SetMultipartRetryCount(int retrycnt) { retry_count = retrycnt; }
bool IsOverMultipartRetryCount(void) const { return (retry_count >= S3fsCurl::retries); }
int GetLastPreHeadSeecKeyPos(void) const { return b_ssekey_pos; }
// methods(variables)
const std::string& GetPath() const { return path; }
const std::string& GetUrl() const { return url; }
const std::string& GetOp() const { return op; }
const headers_t* GetResponseHeaders() const { return &responseHeaders; }
const std::string& GetBodyData() const { return bodydata; }
const std::string& GetHeadData() const { return headdata; }
CURLcode GetCurlCode() const { return curlCode; }
long GetLastResponseCode() const { return LastResponseCode; }
bool SetUseAhbe(bool ahbe);
bool EnableUseAhbe() { return SetUseAhbe(true); }
bool DisableUseAhbe() { return SetUseAhbe(false); }
bool IsUseAhbe() const { return is_use_ahbe; }
};
//----------------------------------------------
// class S3fsMultiCurl
//----------------------------------------------
// Class for lapping multi curl
//
typedef std::map<CURL*, S3fsCurl*> s3fscurlmap_t;
typedef bool (*S3fsMultiSuccessCallback)(S3fsCurl* s3fscurl); // callback for succeed multi request
typedef S3fsCurl* (*S3fsMultiRetryCallback)(S3fsCurl* s3fscurl); // callback for failure and retrying
class S3fsMultiCurl
{
private:
static int max_multireq;
CURLM* hMulti;
s3fscurlmap_t cMap_all; // all of curl requests
s3fscurlmap_t cMap_req; // curl requests are sent
S3fsMultiSuccessCallback SuccessCallback;
S3fsMultiRetryCallback RetryCallback;
private:
bool ClearEx(bool is_all);
int MultiPerform(void);
int MultiRead(void);
public:
S3fsMultiCurl();
~S3fsMultiCurl();
static int SetMaxMultiRequest(int max);
static int GetMaxMultiRequest(void) { return S3fsMultiCurl::max_multireq; }
S3fsMultiSuccessCallback SetSuccessCallback(S3fsMultiSuccessCallback function);
S3fsMultiRetryCallback SetRetryCallback(S3fsMultiRetryCallback function);
bool Clear(void) { return ClearEx(true); }
bool SetS3fsCurlObject(S3fsCurl* s3fscurl);
int Request(void);
};
//----------------------------------------------
// Utility Functions
//----------------------------------------------
std::string GetContentMD5(int fd);
unsigned char* md5hexsum(int fd, off_t start, ssize_t size);
std::string md5sum(int fd, off_t start, ssize_t size);
struct curl_slist* curl_slist_sort_insert(struct curl_slist* list, const char* data);
struct curl_slist* curl_slist_sort_insert(struct curl_slist* list, const char* key, const char* value);
std::string get_sorted_header_keys(const struct curl_slist* list);
std::string get_canonical_headers(const struct curl_slist* list, bool only_amz = false);
bool MakeUrlResource(const char* realpath, std::string& resourcepath, std::string& url);
std::string prepare_url(const char* url);
bool get_object_sse_type(const char* path, sse_type_t& ssetype, std::string& ssevalue); // implement in s3fs.cpp
#endif // S3FS_CURL_H_
/*
@ -488,6 +369,6 @@ bool get_object_sse_type(const char* path, sse_type_t& ssetype, std::string& sse
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

234
src/curl_share.cpp Normal file
View File

@ -0,0 +1,234 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#include "common.h"
#include "s3fs.h"
#include "s3fs_logger.h"
#include "curl_share.h"
//-------------------------------------------------------------------
// Class S3fsCurlShare
//-------------------------------------------------------------------
bool S3fsCurlShare::is_dns_cache = true; // default
bool S3fsCurlShare::is_ssl_cache = true; // default
std::mutex S3fsCurlShare::curl_share_lock;
std::map<std::thread::id, CurlSharePtr> S3fsCurlShare::ShareHandles;
std::map<std::thread::id, ShareLocksPtr> S3fsCurlShare::ShareLocks;
//-------------------------------------------------------------------
// Class methods for S3fsCurlShare
//-------------------------------------------------------------------
bool S3fsCurlShare::SetDnsCache(bool isCache)
{
bool old = S3fsCurlShare::is_dns_cache;
S3fsCurlShare::is_dns_cache = isCache;
return old;
}
bool S3fsCurlShare::SetSslSessionCache(bool isCache)
{
bool old = S3fsCurlShare::is_ssl_cache;
S3fsCurlShare::is_ssl_cache = isCache;
return old;
}
void S3fsCurlShare::LockCurlShare(CURL* handle, curl_lock_data nLockData, curl_lock_access laccess, void* useptr)
{
auto* pLocks = static_cast<curl_share_locks*>(useptr);
if(CURL_LOCK_DATA_DNS == nLockData){
pLocks->lock_dns.lock();
}else if(CURL_LOCK_DATA_SSL_SESSION == nLockData){
pLocks->lock_session.lock();
}
}
void S3fsCurlShare::UnlockCurlShare(CURL* handle, curl_lock_data nLockData, void* useptr)
{
auto* pLocks = static_cast<curl_share_locks*>(useptr);
if(CURL_LOCK_DATA_DNS == nLockData){
pLocks->lock_dns.unlock();
}else if(CURL_LOCK_DATA_SSL_SESSION == nLockData){
pLocks->lock_session.unlock();
}
}
bool S3fsCurlShare::SetCurlShareHandle(CURL* hCurl)
{
if(!hCurl){
S3FS_PRN_ERR("Curl handle is null");
return false;
}
// get curl share handle
S3fsCurlShare CurlShareObj;
CURLSH* hCurlShare = CurlShareObj.GetCurlShareHandle();
if(!hCurlShare){
// a case of not to use CurlShare
return true;
}
// set share handle to curl handle
if(CURLE_OK != curl_easy_setopt(hCurl, CURLOPT_SHARE, hCurlShare)){
S3FS_PRN_ERR("Failed to set Curl share handle to curl handle.");
return false;
}
return true;
}
bool S3fsCurlShare::DestroyCurlShareHandleForThread()
{
S3fsCurlShare CurlShareObj;
CurlShareObj.DestroyCurlShareHandle();
return true;
}
bool S3fsCurlShare::InitializeCurlShare(const CurlSharePtr& hShare, const ShareLocksPtr& ShareLock)
{
CURLSHcode nSHCode;
// set lock handlers
if(CURLSHE_OK != (nSHCode = curl_share_setopt(hShare.get(), CURLSHOPT_LOCKFUNC, S3fsCurlShare::LockCurlShare))){
S3FS_PRN_ERR("curl_share_setopt(LOCKFUNC) returns %d(%s)", nSHCode, curl_share_strerror(nSHCode));
return false;
}
if(CURLSHE_OK != (nSHCode = curl_share_setopt(hShare.get(), CURLSHOPT_UNLOCKFUNC, S3fsCurlShare::UnlockCurlShare))){
S3FS_PRN_ERR("curl_share_setopt(UNLOCKFUNC) returns %d(%s)", nSHCode, curl_share_strerror(nSHCode));
return false;
}
// set user data for lock functions
if(CURLSHE_OK != (nSHCode = curl_share_setopt(hShare.get(), CURLSHOPT_USERDATA, ShareLock.get()))){
S3FS_PRN_ERR("curl_share_setopt(USERDATA) returns %d(%s)", nSHCode, curl_share_strerror(nSHCode));
return false;
}
// set share type
if(S3fsCurlShare::is_dns_cache){
nSHCode = curl_share_setopt(hShare.get(), CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
if(CURLSHE_OK != nSHCode && CURLSHE_BAD_OPTION != nSHCode && CURLSHE_NOT_BUILT_IN != nSHCode){
S3FS_PRN_ERR("curl_share_setopt(DNS) returns %d(%s)", nSHCode, curl_share_strerror(nSHCode));
return false;
}else if(CURLSHE_BAD_OPTION == nSHCode || CURLSHE_NOT_BUILT_IN == nSHCode){
S3FS_PRN_WARN("curl_share_setopt(DNS) returns %d(%s), but continue without shared dns data.", nSHCode, curl_share_strerror(nSHCode));
}
}
if(S3fsCurlShare::is_ssl_cache){
nSHCode = curl_share_setopt(hShare.get(), CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION);
if(CURLSHE_OK != nSHCode && CURLSHE_BAD_OPTION != nSHCode && CURLSHE_NOT_BUILT_IN != nSHCode){
S3FS_PRN_ERR("curl_share_setopt(SSL SESSION) returns %d(%s)", nSHCode, curl_share_strerror(nSHCode));
return false;
}else if(CURLSHE_BAD_OPTION == nSHCode || CURLSHE_NOT_BUILT_IN == nSHCode){
S3FS_PRN_WARN("curl_share_setopt(SSL SESSION) returns %d(%s), but continue without shared ssl session data.", nSHCode, curl_share_strerror(nSHCode));
}
}
return true;
}
//-------------------------------------------------------------------
// Methods for S3fsCurlShare
//-------------------------------------------------------------------
// [NOTE]
// set current thread id(std style) to ThreadId
//
S3fsCurlShare::S3fsCurlShare() : ThreadId(std::this_thread::get_id())
{
}
void S3fsCurlShare::DestroyCurlShareHandle()
{
if(!S3fsCurlShare::is_dns_cache && !S3fsCurlShare::is_ssl_cache){
// Any curl share handle does not exist
return;
}
const std::lock_guard<std::mutex> lock(S3fsCurlShare::curl_share_lock);
// find existed handle and cleanup it
auto handle_iter = S3fsCurlShare::ShareHandles.find(ThreadId);
if(handle_iter == S3fsCurlShare::ShareHandles.end()){
S3FS_PRN_WARN("Not found curl share handle");
}else{
S3fsCurlShare::ShareHandles.erase(handle_iter);
}
// find lock and cleanup it
auto locks_iter = S3fsCurlShare::ShareLocks.find(ThreadId);
if(locks_iter == S3fsCurlShare::ShareLocks.end()){
S3FS_PRN_WARN("Not found locks of curl share handle");
}else{
S3fsCurlShare::ShareLocks.erase(locks_iter);
}
}
CURLSH* S3fsCurlShare::GetCurlShareHandle()
{
if(!S3fsCurlShare::is_dns_cache && !S3fsCurlShare::is_ssl_cache){
// Any curl share handle does not exist
return nullptr;
}
const std::lock_guard<std::mutex> lock(S3fsCurlShare::curl_share_lock);
// find existed handle
auto handle_iter = S3fsCurlShare::ShareHandles.find(ThreadId);
if(handle_iter != S3fsCurlShare::ShareHandles.end()){
// Already created share handle for this thread.
return handle_iter->second.get();
}
// create new curl share handle and locks
CurlSharePtr hShare = {nullptr, curl_share_cleanup};
hShare.reset(curl_share_init());
if(!hShare){
S3FS_PRN_ERR("Failed to create curl share handle");
return nullptr;
}
auto pLocks = std::make_unique<curl_share_locks>();
// Initialize curl share handle
if(!S3fsCurlShare::InitializeCurlShare(hShare, pLocks)){
S3FS_PRN_ERR("Failed to initialize curl share handle");
return nullptr;
}
// set map
S3fsCurlShare::ShareHandles.emplace(ThreadId, std::move(hShare));
S3fsCurlShare::ShareLocks.emplace(ThreadId, std::move(pLocks));
// For clang-tidy measures
handle_iter = S3fsCurlShare::ShareHandles.find(ThreadId);
if(handle_iter == S3fsCurlShare::ShareHandles.end()){
S3FS_PRN_ERR("Failed to insert curl share to map.");
return nullptr;
}
return handle_iter->second.get();
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

89
src/curl_share.h Normal file
View File

@ -0,0 +1,89 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_CURL_SHARE_H_
#define S3FS_CURL_SHARE_H_
#include <curl/curl.h>
#include <map>
#include <memory>
#include <mutex>
#include <thread>
#include "common.h"
//----------------------------------------------
// Structure / Typedefs
//----------------------------------------------
struct curl_share_locks {
std::mutex lock_dns;
std::mutex lock_session;
};
typedef std::unique_ptr<CURLSH, decltype(&curl_share_cleanup)> CurlSharePtr;
typedef std::unique_ptr<curl_share_locks> ShareLocksPtr;
//----------------------------------------------
// class S3fsCurlShare
//----------------------------------------------
class S3fsCurlShare
{
private:
static bool is_dns_cache;
static bool is_ssl_cache;
static std::mutex curl_share_lock;
static std::map<std::thread::id, CurlSharePtr> ShareHandles GUARDED_BY(curl_share_lock);
static std::map<std::thread::id, ShareLocksPtr> ShareLocks GUARDED_BY(curl_share_lock);
std::thread::id ThreadId;
private:
static void LockCurlShare(CURL* handle, curl_lock_data nLockData, curl_lock_access laccess, void* useptr) NO_THREAD_SAFETY_ANALYSIS;
static void UnlockCurlShare(CURL* handle, curl_lock_data nLockData, void* useptr) NO_THREAD_SAFETY_ANALYSIS;
static bool InitializeCurlShare(const CurlSharePtr& hShare, const ShareLocksPtr& ShareLock) REQUIRES(curl_share_lock);
void DestroyCurlShareHandle();
CURLSH* GetCurlShareHandle();
public:
static bool SetDnsCache(bool isCache);
static bool SetSslSessionCache(bool isCache);
static bool SetCurlShareHandle(CURL* hCurl);
static bool DestroyCurlShareHandleForThread();
// constructor/destructor
explicit S3fsCurlShare();
~S3fsCurlShare() = default;
S3fsCurlShare(const S3fsCurlShare&) = delete;
S3fsCurlShare(S3fsCurlShare&&) = delete;
S3fsCurlShare& operator=(const S3fsCurlShare&) = delete;
S3fsCurlShare& operator=(S3fsCurlShare&&) = delete;
};
#endif // S3FS_CURL_SHARE_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

337
src/curl_util.cpp Normal file
View File

@ -0,0 +1,337 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#include <cstdio>
#include <cstdlib>
#include <curl/curl.h>
#include <string>
#include "common.h"
#include "s3fs_logger.h"
#include "curl_util.h"
#include "string_util.h"
#include "s3fs_auth.h"
#include "s3fs_cred.h"
using namespace std::string_literals;
//-------------------------------------------------------------------
// Utility Functions
//-------------------------------------------------------------------
//
// curl_slist_sort_insert
// This function is like curl_slist_append function, but this adds data by a-sorting.
// Because AWS signature needs sorted header.
//
struct curl_slist* curl_slist_sort_insert(struct curl_slist* list, const char* key, const char* value)
{
if(!key){
return list;
}
// key & value are trimmed and lower (only key)
std::string strkey = trim(key);
std::string strval = value ? trim(value) : "";
std::string strnew = key + ": "s + strval;
char* data;
if(nullptr == (data = strdup(strnew.c_str()))){
return list;
}
struct curl_slist **p = &list;
for(;*p; p = &(*p)->next){
std::string strcur = (*p)->data;
size_t pos;
if(std::string::npos != (pos = strcur.find(':', 0))){
strcur.erase(pos);
}
int result = strcasecmp(strkey.c_str(), strcur.c_str());
if(0 == result){
free((*p)->data);
(*p)->data = data;
return list;
}else if(result < 0){
break;
}
}
struct curl_slist* new_item;
// Must use malloc since curl_slist_free_all calls free.
if(nullptr == (new_item = static_cast<struct curl_slist*>(malloc(sizeof(*new_item))))){
free(data);
return list;
}
struct curl_slist* before = *p;
*p = new_item;
new_item->data = data;
new_item->next = before;
return list;
}
struct curl_slist* curl_slist_remove(struct curl_slist* list, const char* key)
{
if(!key){
return list;
}
std::string strkey = trim(key);
struct curl_slist **p = &list;
while(*p){
std::string strcur = (*p)->data;
size_t pos;
if(std::string::npos != (pos = strcur.find(':', 0))){
strcur.erase(pos);
}
int result = strcasecmp(strkey.c_str(), strcur.c_str());
if(0 == result){
free((*p)->data);
struct curl_slist *tmp = *p;
*p = (*p)->next;
free(tmp);
}else{
p = &(*p)->next;
}
}
return list;
}
std::string get_sorted_header_keys(const struct curl_slist* list)
{
std::string sorted_headers;
if(!list){
return sorted_headers;
}
for( ; list; list = list->next){
std::string strkey = list->data;
size_t pos;
if(std::string::npos != (pos = strkey.find(':', 0))){
if (trim(strkey.substr(pos + 1)).empty()) {
// skip empty-value headers (as they are discarded by libcurl)
continue;
}
strkey.erase(pos);
}
if(!sorted_headers.empty()){
sorted_headers += ";";
}
sorted_headers += lower(strkey);
}
return sorted_headers;
}
std::string get_header_value(const struct curl_slist* list, const std::string &key)
{
if(!list){
return "";
}
for( ; list; list = list->next){
std::string strkey = list->data;
size_t pos;
if(std::string::npos != (pos = strkey.find(':', 0))){
if(0 == strcasecmp(trim(strkey.substr(0, pos)).c_str(), key.c_str())){
return trim(strkey.substr(pos+1));
}
}
}
return "";
}
std::string get_canonical_headers(const struct curl_slist* list, bool only_amz)
{
std::string canonical_headers;
if(!list){
canonical_headers = "\n";
return canonical_headers;
}
for( ; list; list = list->next){
std::string strhead = list->data;
size_t pos;
if(std::string::npos != (pos = strhead.find(':', 0))){
std::string strkey = trim(lower(strhead.substr(0, pos)));
std::string strval = trim(strhead.substr(pos + 1));
if (strval.empty()) {
// skip empty-value headers (as they are discarded by libcurl)
continue;
}
strhead = strkey;
strhead += ":";
strhead += strval;
}else{
strhead = trim(lower(strhead));
}
if(only_amz && strhead.substr(0, 5) != "x-amz"){
continue;
}
canonical_headers += strhead;
canonical_headers += "\n";
}
return canonical_headers;
}
// function for using global values
bool MakeUrlResource(const char* realpath, std::string& resourcepath, std::string& url)
{
if(!realpath){
return false;
}
resourcepath = urlEncodePath(service_path + S3fsCred::GetBucket() + realpath);
url = s3host + resourcepath;
return true;
}
std::string prepare_url(const char* url)
{
S3FS_PRN_DBG("URL is %s", url);
std::string uri;
std::string hostname;
std::string path;
std::string url_str = url;
std::string token = "/" + S3fsCred::GetBucket();
size_t bucket_pos;
size_t bucket_length = token.size();
size_t uri_length = 0;
if(!strncasecmp(url_str.c_str(), "https://", 8)){
uri_length = 8;
} else if(!strncasecmp(url_str.c_str(), "http://", 7)) {
uri_length = 7;
}
uri = url_str.substr(0, uri_length);
bucket_pos = url_str.find(token, uri_length);
if(!pathrequeststyle){
hostname = S3fsCred::GetBucket() + "." + url_str.substr(uri_length, bucket_pos - uri_length);
path = url_str.substr((bucket_pos + bucket_length));
}else{
hostname = url_str.substr(uri_length, bucket_pos - uri_length);
std::string part = url_str.substr((bucket_pos + bucket_length));
if('/' != part[0]){
part = "/" + part;
}
path = "/" + S3fsCred::GetBucket() + part;
}
url_str = uri + hostname + path;
S3FS_PRN_DBG("URL changed is %s", url_str.c_str());
return url_str;
}
bool make_md5_from_binary(const char* pstr, size_t length, std::string& md5)
{
if(!pstr || '\0' == pstr[0]){
S3FS_PRN_ERR("Parameter is wrong.");
return false;
}
md5_t binary;
if(!s3fs_md5(reinterpret_cast<const unsigned char*>(pstr), length, &binary)){
return false;
}
md5 = s3fs_base64(binary.data(), binary.size());
return true;
}
std::string url_to_host(const std::string &url)
{
S3FS_PRN_INFO3("url is %s", url.c_str());
static constexpr char HTTP[] = "http://";
static constexpr char HTTPS[] = "https://";
std::string hostname;
if (is_prefix(url.c_str(), HTTP)) {
hostname = url.substr(sizeof(HTTP) - 1);
} else if (is_prefix(url.c_str(), HTTPS)) {
hostname = url.substr(sizeof(HTTPS) - 1);
} else {
S3FS_PRN_EXIT("url does not begin with http:// or https://");
abort();
}
size_t idx;
if ((idx = hostname.find('/')) != std::string::npos) {
return hostname.substr(0, idx);
} else {
return hostname;
}
}
std::string get_bucket_host()
{
if(!pathrequeststyle){
return S3fsCred::GetBucket() + "." + url_to_host(s3host);
}
return url_to_host(s3host);
}
const char* getCurlDebugHead(curl_infotype type)
{
const char* unknown = "";
const char* dataIn = "BODY <";
const char* dataOut = "BODY >";
const char* headIn = "<";
const char* headOut = ">";
switch(type){
case CURLINFO_DATA_IN:
return dataIn;
case CURLINFO_DATA_OUT:
return dataOut;
case CURLINFO_HEADER_IN:
return headIn;
case CURLINFO_HEADER_OUT:
return headOut;
default:
break;
}
return unknown;
}
//
// compare ETag ignoring quotes and case
//
bool etag_equals(const std::string& s1, const std::string& s2)
{
return 0 == strcasecmp(peeloff(s1).c_str(), peeloff(s2).c_str());
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

60
src/curl_util.h Normal file
View File

@ -0,0 +1,60 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_CURL_UTIL_H_
#define S3FS_CURL_UTIL_H_
#include <cstdint>
#include <curl/curl.h>
#include <string>
#include "metaheader.h"
enum class sse_type_t : uint8_t;
//----------------------------------------------
// Functions
//----------------------------------------------
struct curl_slist* curl_slist_sort_insert(struct curl_slist* list, const char* key, const char* value);
struct curl_slist* curl_slist_remove(struct curl_slist* list, const char* key);
std::string get_sorted_header_keys(const struct curl_slist* list);
std::string get_canonical_headers(const struct curl_slist* list, bool only_amz = false);
std::string get_header_value(const struct curl_slist* list, const std::string &key);
bool MakeUrlResource(const char* realpath, std::string& resourcepath, std::string& url);
std::string prepare_url(const char* url);
bool get_object_sse_type(const char* path, sse_type_t& ssetype, std::string& ssevalue); // implement in s3fs.cpp
int put_headers(const char* path, const headers_t& meta, bool is_copy, bool use_st_size = true); // implement in s3fs.cpp
bool make_md5_from_binary(const char* pstr, size_t length, std::string& md5);
std::string url_to_host(const std::string &url);
std::string get_bucket_host();
const char* getCurlDebugHead(curl_infotype type);
bool etag_equals(const std::string& s1, const std::string& s2);
#endif // S3FS_CURL_UTIL_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright 2007-2008 Randy Rizun <rrizun@gmail.com>
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -17,161 +17,16 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef FD_CACHE_H_
#define FD_CACHE_H_
#include <sys/statvfs.h>
#include "curl.h"
#ifndef S3FS_FDCACHE_H_
#define S3FS_FDCACHE_H_
//------------------------------------------------
// CacheFileStat
//------------------------------------------------
class CacheFileStat
{
private:
std::string path;
int fd;
#include <mutex>
#include <string>
private:
static bool MakeCacheFileStatPath(const char* path, std::string& sfile_path, bool is_create_dir = true);
public:
static bool DeleteCacheFileStat(const char* path);
static bool CheckCacheFileStatTopDir(void);
static bool DeleteCacheFileStatDirectory(void);
explicit CacheFileStat(const char* tpath = NULL);
~CacheFileStat();
bool Open(void);
bool Release(void);
bool SetPath(const char* tpath, bool is_open = true);
int GetFd(void) const { return fd; }
};
//------------------------------------------------
// fdpage & PageList
//------------------------------------------------
// page block information
struct fdpage
{
off_t offset;
size_t bytes;
bool loaded;
fdpage(off_t start = 0, size_t size = 0, bool is_loaded = false)
: offset(start), bytes(size), loaded(is_loaded) {}
off_t next(void) const { return (offset + bytes); }
off_t end(void) const { return (0 < bytes ? offset + bytes - 1 : 0); }
};
typedef std::list<struct fdpage*> fdpage_list_t;
class FdEntity;
//
// Management of loading area/modifying
//
class PageList
{
friend class FdEntity; // only one method access directly pages.
private:
fdpage_list_t pages;
private:
void Clear(void);
bool Compress(void);
bool Parse(off_t new_pos);
public:
static void FreeList(fdpage_list_t& list);
explicit PageList(size_t size = 0, bool is_loaded = false);
~PageList();
bool Init(size_t size, bool is_loaded);
size_t Size(void) const;
bool Resize(size_t size, bool is_loaded);
bool IsPageLoaded(off_t start = 0, size_t size = 0) const; // size=0 is checking to end of list
bool SetPageLoadedStatus(off_t start, size_t size, bool is_loaded = true, bool is_compress = true);
bool FindUnloadedPage(off_t start, off_t& resstart, size_t& ressize) const;
size_t GetTotalUnloadedPageSize(off_t start = 0, size_t size = 0) const; // size=0 is checking to end of list
int GetUnloadedPages(fdpage_list_t& unloaded_list, off_t start = 0, size_t size = 0) const; // size=0 is checking to end of list
bool Serialize(CacheFileStat& file, bool is_output);
void Dump(void);
};
//------------------------------------------------
// class FdEntity
//------------------------------------------------
class FdEntity
{
private:
pthread_mutex_t fdent_lock;
bool is_lock_init;
PageList pagelist;
int refcnt; // reference count
std::string path; // object path
std::string cachepath; // local cache file path
// (if this is empty, does not load/save pagelist.)
int fd; // file descriptor(tmp file or cache file)
FILE* pfile; // file pointer(tmp file or cache file)
bool is_modify; // if file is changed, this flag is true
headers_t orgmeta; // original headers at opening
size_t size_orgmeta; // original file size in original headers
std::string upload_id; // for no cached multipart uploading when no disk space
etaglist_t etaglist; // for no cached multipart uploading when no disk space
off_t mp_start; // start position for no cached multipart(write method only)
size_t mp_size; // size for no cached multipart(write method only)
private:
static int FillFile(int fd, unsigned char byte, size_t size, off_t start);
void Clear(void);
bool SetAllStatus(bool is_loaded); // [NOTE] not locking
//bool SetAllStatusLoaded(void) { return SetAllStatus(true); }
bool SetAllStatusUnloaded(void) { return SetAllStatus(false); }
public:
explicit FdEntity(const char* tpath = NULL, const char* cpath = NULL);
~FdEntity();
void Close(void);
bool IsOpen(void) const { return (-1 != fd); }
int Open(headers_t* pmeta = NULL, ssize_t size = -1, time_t time = -1);
bool OpenAndLoadAll(headers_t* pmeta = NULL, size_t* size = NULL, bool force_load = false);
int Dup(void);
const char* GetPath(void) const { return path.c_str(); }
void SetPath(const std::string &newpath) { path = newpath; }
int GetFd(void) const { return fd; }
bool GetStats(struct stat& st);
int SetMtime(time_t time);
bool UpdateMtime(void);
bool GetSize(size_t& size);
bool SetMode(mode_t mode);
bool SetUId(uid_t uid);
bool SetGId(gid_t gid);
bool SetContentType(const char* path);
int Load(off_t start = 0, size_t size = 0); // size=0 means loading to end
int NoCacheLoadAndPost(off_t start = 0, size_t size = 0); // size=0 means loading to end
int NoCachePreMultipartPost(void);
int NoCacheMultipartPost(int tgfd, off_t start, size_t size);
int NoCacheCompleteMultipartPost(void);
int RowFlush(const char* tpath, bool force_sync = false);
int Flush(bool force_sync = false) { return RowFlush(NULL, force_sync); }
ssize_t Read(char* bytes, off_t start, size_t size, bool force_load = false);
ssize_t Write(const char* bytes, off_t start, size_t size);
};
typedef std::map<std::string, class FdEntity*> fdent_map_t; // key=path, value=FdEntity*
#include "common.h"
#include "fdcache_entity.h"
#include "s3fs_util.h"
//------------------------------------------------
// class FdManager
@ -179,53 +34,101 @@ typedef std::map<std::string, class FdEntity*> fdent_map_t; // key=path, value
class FdManager
{
private:
static FdManager singleton;
static pthread_mutex_t fd_manager_lock;
static bool is_lock_init;
static std::string cache_dir;
static size_t free_disk_space; // limit free disk space
static FdManager singleton;
static std::mutex fd_manager_lock;
static std::mutex cache_cleanup_lock;
static std::mutex reserved_diskspace_lock;
static std::mutex except_entmap_lock;
static std::string cache_dir;
static bool check_cache_dir_exist;
static off_t free_disk_space GUARDED_BY(reserved_diskspace_lock); // limit free disk space
static off_t fake_used_disk_space GUARDED_BY(reserved_diskspace_lock); // difference between fake free disk space and actual at startup(for test/debug)
static std::string check_cache_output;
static bool checked_lseek;
static bool have_lseek_hole;
static std::string tmp_dir;
fdent_map_t fent;
fdent_map_t fent GUARDED_BY(fd_manager_lock);
fdent_map_t except_fent GUARDED_BY(except_entmap_lock); // A map of delayed deletion fdentity
private:
static fsblkcnt_t GetFreeDiskSpace(const char* path);
static off_t GetFreeDiskSpaceHasLock(const char* path) REQUIRES(FdManager::reserved_diskspace_lock);
static off_t GetTotalDiskSpace(const char* path);
static bool IsDir(const std::string& dir);
static int GetVfsStat(const char* path, struct statvfs* vfsbuf);
static off_t GetEnsureFreeDiskSpaceHasLock() REQUIRES(FdManager::reserved_diskspace_lock);
// Returns the number of open pseudo fd.
int GetPseudoFdCount(const char* path) REQUIRES(fd_manager_lock);
bool UpdateEntityToTempPath() REQUIRES(fd_manager_lock);
void CleanupCacheDirInternal(const std::string &path = "") REQUIRES(cache_cleanup_lock);
bool RawCheckAllCache(FILE* fp, const char* cache_stat_top_dir, const char* sub_path, int& total_file_cnt, int& err_file_cnt, int& err_dir_cnt);
public:
FdManager();
~FdManager();
FdManager();
~FdManager();
FdManager(const FdManager&) = delete;
FdManager(FdManager&&) = delete;
FdManager& operator=(const FdManager&) = delete;
FdManager& operator=(FdManager&&) = delete;
// Reference singleton
static FdManager* get(void) { return &singleton; }
// Reference singleton
static FdManager* get() { return &singleton; }
static bool DeleteCacheDirectory(void);
static int DeleteCacheFile(const char* path);
static bool SetCacheDir(const char* dir);
static bool IsCacheDir(void) { return (0 < FdManager::cache_dir.size()); }
static const char* GetCacheDir(void) { return FdManager::cache_dir.c_str(); }
static bool MakeCachePath(const char* path, std::string& cache_path, bool is_create_dir = true);
static bool CheckCacheTopDir(void);
static bool MakeRandomTempPath(const char* path, std::string& tmppath);
static bool DeleteCacheDirectory();
static int DeleteCacheFile(const char* path);
static bool SetCacheDir(const char* dir);
static bool IsCacheDir() { return !FdManager::cache_dir.empty(); }
static const char* GetCacheDir() { return FdManager::cache_dir.c_str(); }
static bool SetCacheCheckOutput(const char* path);
static const char* GetCacheCheckOutput() { return FdManager::check_cache_output.c_str(); }
static bool MakeCachePath(const char* path, std::string& cache_path, bool is_create_dir = true, bool is_mirror_path = false);
static bool CheckCacheTopDir();
static bool MakeRandomTempPath(const char* path, std::string& tmppath);
static bool SetCheckCacheDirExist(bool is_check);
static bool CheckCacheDirExist();
static bool HasOpenEntityFd(const char* path);
static int GetOpenFdCount(const char* path);
static off_t GetEnsureFreeDiskSpace()
{
const std::lock_guard<std::mutex> lock(FdManager::reserved_diskspace_lock);
return FdManager::GetEnsureFreeDiskSpaceHasLock();
}
static off_t SetEnsureFreeDiskSpace(off_t size);
static bool InitFakeUsedDiskSize(off_t fake_freesize);
static bool IsSafeDiskSpace(const char* path, off_t size, bool withmsg = false);
static void FreeReservedDiskSpace(off_t size);
static bool ReserveDiskSpace(off_t size);
static bool HaveLseekHole();
static bool SetTmpDir(const char* dir);
static bool CheckTmpDirExist();
static std::unique_ptr<FILE, decltype(&s3fs_fclose)> MakeTempFile();
static off_t GetTotalDiskSpaceByRatio(int ratio);
static size_t GetEnsureFreeDiskSpace(void) { return FdManager::free_disk_space; }
static size_t SetEnsureFreeDiskSpace(size_t size);
static size_t InitEnsureFreeDiskSpace(void) { return SetEnsureFreeDiskSpace(0); }
static bool IsSafeDiskSpace(const char* path, size_t size);
// Return FdEntity associated with path, returning nullptr on error. This operation increments the reference count; callers must decrement via Close after use.
FdEntity* GetFdEntity(const char* path, int& existfd, bool newfd = true) {
const std::lock_guard<std::mutex> lock(FdManager::fd_manager_lock);
return GetFdEntityHasLock(path, existfd, newfd);
}
FdEntity* GetFdEntityHasLock(const char* path, int& existfd, bool newfd = true) REQUIRES(FdManager::fd_manager_lock);
FdEntity* Open(int& fd, const char* path, const headers_t* pmeta, off_t size, const FileTimes& ts_times, int flags, bool force_tmpfile, bool is_create, bool ignore_modify);
FdEntity* GetExistFdEntity(const char* path, int existfd = -1);
FdEntity* OpenExistFdEntity(const char* path, int& fd, int flags = O_RDONLY);
void Rename(const std::string &from, const std::string &to);
bool Close(FdEntity* ent, int fd);
bool ChangeEntityToTempPath(std::shared_ptr<FdEntity> ent, const char* path);
void CleanupCacheDir();
FdEntity* GetFdEntity(const char* path, int existfd = -1);
FdEntity* Open(const char* path, headers_t* pmeta = NULL, ssize_t size = -1, time_t time = -1, bool force_tmpfile = false, bool is_create = true);
FdEntity* ExistOpen(const char* path, int existfd = -1, bool ignore_existfd = false);
void Rename(const std::string &from, const std::string &to);
bool Close(FdEntity* ent);
bool ChangeEntityToTempPath(FdEntity* ent, const char* path);
bool CheckAllCache();
};
#endif // FD_CACHE_H_
#endif // S3FS_FDCACHE_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

126
src/fdcache_auto.cpp Normal file
View File

@ -0,0 +1,126 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Takeshi Nakatani <ggtakec.com>
*
* 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.
*/
#include <cstdio>
#include "s3fs_logger.h"
#include "fdcache_auto.h"
#include "fdcache.h"
//------------------------------------------------
// AutoFdEntity methods
//------------------------------------------------
AutoFdEntity::AutoFdEntity() : pFdEntity(nullptr), pseudo_fd(-1)
{
}
AutoFdEntity::~AutoFdEntity()
{
Close();
}
bool AutoFdEntity::Close()
{
if(pFdEntity){
if(!FdManager::get()->Close(pFdEntity, pseudo_fd)){
S3FS_PRN_ERR("Failed to close fdentity.");
return false;
}
pFdEntity = nullptr;
pseudo_fd = -1;
}
return true;
}
// [NOTE]
// This method touches the internal fdentity with.
// This is used to keep the file open.
//
int AutoFdEntity::Detach()
{
if(!pFdEntity){
S3FS_PRN_ERR("Does not have a associated FdEntity.");
return -1;
}
int fd = pseudo_fd;
pseudo_fd = -1;
pFdEntity = nullptr;
return fd;
}
FdEntity* AutoFdEntity::Attach(const char* path, int existfd)
{
Close();
if(nullptr == (pFdEntity = FdManager::get()->GetFdEntity(path, existfd, false))){
S3FS_PRN_DBG("Could not find fd entity object(file=%s, pseudo_fd=%d)", path, existfd);
return nullptr;
}
pseudo_fd = existfd;
return pFdEntity;
}
FdEntity* AutoFdEntity::Open(const char* path, const headers_t* pmeta, off_t size, const FileTimes& ts_times, int flags, bool force_tmpfile, bool is_create, bool ignore_modify, int* error)
{
Close();
if(nullptr == (pFdEntity = FdManager::get()->Open(pseudo_fd, path, pmeta, size, ts_times, flags, force_tmpfile, is_create, ignore_modify))){
if(error){
*error = pseudo_fd;
}
pseudo_fd = -1;
return nullptr;
}
return pFdEntity;
}
// [NOTE]
// the fd obtained by this method is not a newly created pseudo fd.
//
FdEntity* AutoFdEntity::GetExistFdEntity(const char* path, int existfd)
{
Close();
FdEntity* ent;
if(nullptr == (ent = FdManager::get()->GetExistFdEntity(path, existfd))){
return nullptr;
}
return ent;
}
FdEntity* AutoFdEntity::OpenExistFdEntity(const char* path, int flags)
{
Close();
if(nullptr == (pFdEntity = FdManager::get()->OpenExistFdEntity(path, pseudo_fd, flags))){
return nullptr;
}
return pFdEntity;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

73
src/fdcache_auto.h Normal file
View File

@ -0,0 +1,73 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_FDCACHE_AUTO_H_
#define S3FS_FDCACHE_AUTO_H_
#include <fcntl.h>
#include "common.h"
#include "metaheader.h"
#include "filetimes.h"
class FdEntity;
//------------------------------------------------
// class AutoFdEntity
//------------------------------------------------
// A class that opens fdentry and closes it automatically.
// This class object is used to prevent inconsistencies in
// the number of references in fdentry.
// The methods are wrappers to the method of the FdManager class.
//
class AutoFdEntity
{
private:
FdEntity* pFdEntity;
int pseudo_fd;
public:
AutoFdEntity();
~AutoFdEntity();
AutoFdEntity(const AutoFdEntity&) = delete;
AutoFdEntity(AutoFdEntity&&) = delete;
AutoFdEntity& operator=(const AutoFdEntity&) = delete;
AutoFdEntity& operator=(AutoFdEntity&&) = delete;
bool Close();
int Detach();
FdEntity* Attach(const char* path, int existfd);
int GetPseudoFd() const { return pseudo_fd; }
FdEntity* Open(const char* path, const headers_t* pmeta, off_t size, const FileTimes& ts_times, int flags, bool force_tmpfile, bool is_create, bool ignore_modify, int* error = nullptr);
FdEntity* GetExistFdEntity(const char* path, int existfd = -1);
FdEntity* OpenExistFdEntity(const char* path, int flags = O_RDONLY);
};
#endif // S3FS_FDCACHE_AUTO_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

2608
src/fdcache_entity.cpp Normal file

File diff suppressed because it is too large Load Diff

267
src/fdcache_entity.h Normal file
View File

@ -0,0 +1,267 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_FDCACHE_ENTITY_H_
#define S3FS_FDCACHE_ENTITY_H_
#include <cstdint>
#include <fcntl.h>
#include <memory>
#include <mutex>
#include <string>
#include "common.h"
#include "fdcache_page.h"
#include "fdcache_untreated.h"
#include "metaheader.h"
#include "s3fs_util.h"
#include "filetimes.h"
//----------------------------------------------
// Typedef
//----------------------------------------------
class PseudoFdInfo;
typedef std::map<int, std::unique_ptr<PseudoFdInfo>> fdinfo_map_t;
//------------------------------------------------
// class FdEntity
//------------------------------------------------
class FdEntity : public std::enable_shared_from_this<FdEntity>
{
private:
// [NOTE]
// Distinguish between meta pending and new file creation pending,
// because the processing(request) at these updates is different.
// Therefore, the pending state is expressed by this enum type.
//
enum class pending_status_t : uint8_t {
NO_UPDATE_PENDING = 0,
UPDATE_META_PENDING, // pending meta header
CREATE_FILE_PENDING // pending file creation and meta header
};
static bool mixmultipart; // whether multipart uploading can use copy api.
static bool streamupload; // whether stream uploading.
mutable std::mutex fdent_lock;
std::string path GUARDED_BY(fdent_lock); // object path
int physical_fd GUARDED_BY(fdent_lock); // physical file(cache or temporary file) descriptor
UntreatedParts untreated_list GUARDED_BY(fdent_lock); // list of untreated parts that have been written and not yet uploaded(for streamupload)
fdinfo_map_t pseudo_fd_map GUARDED_BY(fdent_lock); // pseudo file descriptor information map
std::unique_ptr<FILE, decltype(&s3fs_fclose)> pfile GUARDED_BY(fdent_lock) = {nullptr, &s3fs_fclose}; // file pointer(tmp file or cache file)
ino_t inode GUARDED_BY(fdent_lock); // inode number for cache file
headers_t orgmeta GUARDED_BY(fdent_lock); // original headers at opening
off_t size_orgmeta GUARDED_BY(fdent_lock); // original file size in original headers
mutable std::mutex fdent_data_lock ACQUIRED_AFTER(fdent_lock); // protects the following members
PageList pagelist GUARDED_BY(fdent_data_lock);
std::string cachepath GUARDED_BY(fdent_data_lock); // local cache file path
// (if this is empty, does not load/save pagelist.)
std::string mirrorpath GUARDED_BY(fdent_data_lock); // mirror file path to local cache file path
pending_status_t pending_status GUARDED_BY(fdent_data_lock); // status for new file creation and meta update
FileTimes timestamps GUARDED_BY(fdent_data_lock); // file timestamps(atime/ctime/mtime)
mutable std::mutex ro_path_lock; // for only the ro_path variable
std::string ro_path GUARDED_BY(ro_path_lock); // holds the same value as "path". this is used as a backup(read-only variable) by special functions only.
private:
static int FillFile(int fd, unsigned char byte, off_t size, off_t start);
static ino_t GetInode(int fd);
void Clear();
ino_t GetInode() const REQUIRES(FdEntity::fdent_data_lock);
int OpenMirrorFile() REQUIRES(FdEntity::fdent_data_lock);
int NoCacheLoadAndPost(PseudoFdInfo* pseudo_obj, off_t start = 0, off_t size = 0) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock); // size=0 means loading to end
PseudoFdInfo* CheckPseudoFdFlags(int fd, bool writable) REQUIRES(FdEntity::fdent_lock);
bool IsUploading() REQUIRES(FdEntity::fdent_lock);
int SetCtimeHasLock(struct timespec time) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
int SetAtimeHasLock(struct timespec time) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
int SetMtimeHasLock(struct timespec time) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
int SetFileTimesHasLock(const FileTimes& ts_times) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
bool SetAllStatus(bool is_loaded) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
bool SetAllStatusUnloaded() REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock) { return SetAllStatus(false); }
int PreMultipartUploadRequest(PseudoFdInfo* pseudo_obj) REQUIRES(FdEntity::fdent_lock, fdent_data_lock);
int NoCachePreMultipartUploadRequest(PseudoFdInfo* pseudo_obj) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
int NoCacheMultipartUploadRequest(PseudoFdInfo* pseudo_obj, int tgfd, off_t start, off_t size) REQUIRES(FdEntity::fdent_lock);
int NoCacheMultipartUploadComplete(PseudoFdInfo* pseudo_obj) REQUIRES(FdEntity::fdent_lock);
int RowFlushHasLock(int fd, const char* tpath, bool force_sync) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
int RowFlushNoMultipart(const PseudoFdInfo* pseudo_obj, const char* tpath) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
int RowFlushMultipart(PseudoFdInfo* pseudo_obj, const char* tpath) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
int RowFlushMixMultipart(PseudoFdInfo* pseudo_obj, const char* tpath) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
int RowFlushStreamMultipart(PseudoFdInfo* pseudo_obj, const char* tpath) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
ssize_t WriteNoMultipart(const PseudoFdInfo* pseudo_obj, const char* bytes, off_t start, size_t size) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
ssize_t WriteMultipart(PseudoFdInfo* pseudo_obj, const char* bytes, off_t start, size_t size) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
ssize_t WriteMixMultipart(PseudoFdInfo* pseudo_obj, const char* bytes, off_t start, size_t size) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
ssize_t WriteStreamUpload(PseudoFdInfo* pseudo_obj, const char* bytes, off_t start, size_t size) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
int UploadPendingHasLock(int fd) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
bool ReserveDiskSpace(off_t size) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock);
bool AddUntreated(off_t start, off_t size) REQUIRES(FdEntity::fdent_lock);
bool IsDirtyMetadata() const REQUIRES(FdEntity::fdent_data_lock);
std::shared_ptr<FdEntity> get_shared_ptr() { return shared_from_this(); }
public:
static bool GetNoMixMultipart() { return mixmultipart; }
static bool SetNoMixMultipart();
static bool GetStreamUpload() { return streamupload; }
static bool SetStreamUpload(bool isstream);
explicit FdEntity(const char* tpath = nullptr, const char* cpath = nullptr);
~FdEntity();
FdEntity(const FdEntity&) = delete;
FdEntity(FdEntity&&) = delete;
FdEntity& operator=(const FdEntity&) = delete;
FdEntity& operator=(FdEntity&&) = delete;
void Close(int fd);
bool IsOpen() const {
const std::lock_guard<std::mutex> lock(fdent_lock);
return (-1 != physical_fd);
}
bool FindPseudoFd(int fd) const {
const std::lock_guard<std::mutex> lock(fdent_lock);
return FindPseudoFdWithLock(fd);
}
bool FindPseudoFdWithLock(int fd) const REQUIRES(FdEntity::fdent_lock);
std::string GetROPath() const {
const std::lock_guard<std::mutex> ro_lock(ro_path_lock);
return ro_path;
}
int Open(const headers_t* pmeta, off_t size, const FileTimes& ts_times, int flags);
bool LoadAll(int fd, off_t* size = nullptr, bool force_load = false);
int Dup(int fd) {
const std::lock_guard<std::mutex> lock(fdent_lock);
return DupWithLock(fd);
}
int DupWithLock(int fd) REQUIRES(FdEntity::fdent_lock);
int OpenPseudoFd(int flags = O_RDONLY);
int GetOpenCount() const {
const std::lock_guard<std::mutex> lock(fdent_lock);
return GetOpenCountHasLock();
}
int GetOpenCountHasLock() const REQUIRES(FdEntity::fdent_lock);
std::string GetPath() const
{
const std::lock_guard<std::mutex> lock(fdent_lock);
return path;
}
bool RenamePath(const std::string& newpath, std::string& fentmapkey);
int GetPhysicalFd() const REQUIRES(FdEntity::fdent_lock) { return physical_fd; }
bool IsModified() const;
bool MergeOrgMeta(headers_t& updatemeta);
bool GetOrgMeta(headers_t& meta) const;
int UploadPending(int fd) {
const std::lock_guard<std::mutex> lock(fdent_lock);
const std::lock_guard<std::mutex> lock_data(fdent_data_lock);
return UploadPendingHasLock(fd);
}
bool HaveUploadPending(){
const std::lock_guard<std::mutex> lock_data(fdent_data_lock);
return (pending_status_t::NO_UPDATE_PENDING != pending_status);
}
bool GetStats(struct stat& st) const {
const std::lock_guard<std::mutex> lock(fdent_lock);
return GetStatsHasLock(st);
}
bool GetStatsHasLock(struct stat& st) const REQUIRES(FdEntity::fdent_lock);
int SetCtime(struct timespec time) {
const std::lock_guard<std::mutex> lock(fdent_lock);
const std::lock_guard<std::mutex> lock2(fdent_data_lock);
return SetCtimeHasLock(time);
}
int SetAtime(struct timespec time) {
const std::lock_guard<std::mutex> lock(fdent_lock);
const std::lock_guard<std::mutex> lock2(fdent_data_lock);
return SetAtimeHasLock(time);
}
int SetMtime(struct timespec time) {
const std::lock_guard<std::mutex> lock(fdent_lock);
const std::lock_guard<std::mutex> lock2(fdent_data_lock);
return SetMtimeHasLock(time);
}
bool GetSize(off_t& size) const;
bool GetXattr(std::string& xattr) const;
bool SetXattr(const std::string& xattr);
bool SetMode(mode_t mode) {
const std::lock_guard<std::mutex> lock(fdent_lock);
return SetModeHasLock(mode);
}
bool SetModeHasLock(mode_t mode) REQUIRES(FdEntity::fdent_lock);
bool SetUId(uid_t uid) {
const std::lock_guard<std::mutex> lock(fdent_lock);
return SetUIdHasLock(uid);
}
bool SetUIdHasLock(uid_t uid) REQUIRES(FdEntity::fdent_lock);
bool SetGId(gid_t gid) {
const std::lock_guard<std::mutex> lock(fdent_lock);
return SetGIdHasLock(gid);
}
bool SetGIdHasLock(gid_t gid) REQUIRES(FdEntity::fdent_lock);
bool SetContentType(const char* path);
bool GetStatsFromMeta(struct stat& st) const;
int Load(off_t start, off_t size, bool is_modified_flag = false) REQUIRES(FdEntity::fdent_lock, FdEntity::fdent_data_lock); // size=0 means loading to end
off_t BytesModified();
int RowFlush(int fd, const char* tpath, bool force_sync = false) {
const std::lock_guard<std::mutex> lock(fdent_lock);
const std::lock_guard<std::mutex> lock_data(fdent_data_lock);
return RowFlushHasLock(fd, tpath, force_sync);
}
int Flush(int fd, bool force_sync = false) {
return RowFlush(fd, nullptr, force_sync);
}
ssize_t Read(int fd, char* bytes, off_t start, size_t size, bool force_load = false);
ssize_t Write(int fd, const char* bytes, off_t start, size_t size);
bool PunchHole(off_t start = 0, size_t size = 0);
void MarkDirtyNewFile();
bool IsDirtyNewFile() const;
void MarkDirtyMetadata();
bool GetLastUpdateUntreatedPart(off_t& start, off_t& size) const REQUIRES(FdEntity::fdent_lock);
bool ReplaceLastUpdateUntreatedPart(off_t front_start, off_t front_size, off_t behind_start, off_t behind_size) REQUIRES(FdEntity::fdent_lock);
// Intentionally unimplemented -- for lock checking only.
std::mutex* GetMutex() RETURN_CAPABILITY(fdent_lock);
};
typedef std::map<std::string, std::shared_ptr<FdEntity>> fdent_map_t; // key=path, value=FdEntity
#endif // S3FS_FDCACHE_ENTITY_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

981
src/fdcache_fdinfo.cpp Normal file
View File

@ -0,0 +1,981 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Takeshi Nakatani <ggtakec.com>
*
* 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.
*/
#include <algorithm>
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <memory>
#include <mutex>
#include <string>
#include <sys/stat.h>
#include <unistd.h>
#include "common.h"
#include "s3fs.h"
#include "s3fs_logger.h"
#include "s3fs_util.h"
#include "fdcache_fdinfo.h"
#include "fdcache_pseudofd.h"
#include "fdcache_entity.h"
#include "curl.h"
#include "string_util.h"
#include "threadpoolman.h"
#include "s3fs_threadreqs.h"
//------------------------------------------------
// PseudoFdInfo methods
//------------------------------------------------
PseudoFdInfo::PseudoFdInfo(int fd, int open_flags) : pseudo_fd(-1), physical_fd(fd), flags(0), upload_fd(-1), instruct_count(0), last_result(0), uploaded_sem(0)
{
if(-1 != physical_fd){
pseudo_fd = PseudoFdManager::Get();
flags = open_flags;
}
}
PseudoFdInfo::~PseudoFdInfo()
{
Clear(); // call before destroying the mutex
}
bool PseudoFdInfo::Clear()
{
// cppcheck-suppress unmatchedSuppression
// cppcheck-suppress knownConditionTrueFalse
if(!CancelAllThreads()){
return false;
}
{
const std::lock_guard<std::mutex> lock(upload_list_lock);
// cppcheck-suppress unmatchedSuppression
// cppcheck-suppress knownConditionTrueFalse
if(!ResetUploadInfo()){
return false;
}
}
CloseUploadFd();
if(-1 != pseudo_fd){
PseudoFdManager::Release(pseudo_fd);
}
pseudo_fd = -1;
physical_fd = -1;
return true;
}
bool PseudoFdInfo::IsUploadingHasLock() const
{
return !upload_id.empty();
}
bool PseudoFdInfo::IsUploading() const
{
const std::lock_guard<std::mutex> lock(upload_list_lock);
return IsUploadingHasLock();
}
void PseudoFdInfo::CloseUploadFd()
{
const std::lock_guard<std::mutex> lock(upload_list_lock);
if(-1 != upload_fd){
close(upload_fd);
}
}
bool PseudoFdInfo::OpenUploadFd()
{
const std::lock_guard<std::mutex> lock(upload_list_lock);
if(-1 != upload_fd){
// already initialized
return true;
}
if(-1 == physical_fd){
S3FS_PRN_ERR("physical_fd is not initialized yet.");
return false;
}
// duplicate fd
int fd;
if(-1 == (fd = dup(physical_fd))){
S3FS_PRN_ERR("Could not duplicate physical file descriptor(errno=%d)", errno);
return false;
}
scope_guard guard([&]() { close(fd); });
if(0 != lseek(fd, 0, SEEK_SET)){
S3FS_PRN_ERR("Could not seek physical file descriptor(errno=%d)", errno);
return false;
}
struct stat st;
if(-1 == fstat(fd, &st)){
S3FS_PRN_ERR("Invalid file descriptor for uploading(errno=%d)", errno);
return false;
}
guard.dismiss();
upload_fd = fd;
return true;
}
bool PseudoFdInfo::Set(int fd, int open_flags)
{
if(-1 == fd){
return false;
}
Clear();
physical_fd = fd;
pseudo_fd = PseudoFdManager::Get();
flags = open_flags;
return true;
}
bool PseudoFdInfo::Writable() const
{
if(-1 == pseudo_fd){
return false;
}
if(0 == (flags & (O_WRONLY | O_RDWR))){
return false;
}
return true;
}
bool PseudoFdInfo::Readable() const
{
if(-1 == pseudo_fd){
return false;
}
// O_RDONLY is 0x00, it means any pattern is readable.
return true;
}
bool PseudoFdInfo::ClearUploadInfo(bool is_cancel_mp)
{
if(is_cancel_mp){
// cppcheck-suppress unmatchedSuppression
// cppcheck-suppress knownConditionTrueFalse
if(!CancelAllThreads()){
return false;
}
}
const std::lock_guard<std::mutex> lock(upload_list_lock);
return ResetUploadInfo();
}
bool PseudoFdInfo::ResetUploadInfo()
{
upload_id.clear();
upload_list.clear();
instruct_count = 0;
last_result = 0;
return true;
}
bool PseudoFdInfo::RowInitialUploadInfo(const std::string& id, bool is_cancel_mp)
{
if(is_cancel_mp){
// cppcheck-suppress unmatchedSuppression
// cppcheck-suppress knownConditionTrueFalse
if(!ClearUploadInfo(is_cancel_mp)){
return false;
}
}else{
const std::lock_guard<std::mutex> lock(upload_list_lock);
// cppcheck-suppress unmatchedSuppression
// cppcheck-suppress knownConditionTrueFalse
if(!ResetUploadInfo()){
return false;
}
}
const std::lock_guard<std::mutex> lock(upload_list_lock);
upload_id = id;
return true;
}
void PseudoFdInfo::IncreaseInstructionCount()
{
const std::lock_guard<std::mutex> lock(upload_list_lock);
++instruct_count;
}
bool PseudoFdInfo::GetUploadInfo(std::string& id, int& fd) const
{
const std::lock_guard<std::mutex> lock(upload_list_lock);
if(!IsUploadingHasLock()){
S3FS_PRN_ERR("Multipart Upload has not started yet.");
return false;
}
id = upload_id;
fd = upload_fd;
return true;
}
bool PseudoFdInfo::GetUploadId(std::string& id) const
{
int fd = -1;
return GetUploadInfo(id, fd);
}
bool PseudoFdInfo::GetEtaglist(etaglist_t& list) const
{
const std::lock_guard<std::mutex> lock(upload_list_lock);
if(!IsUploadingHasLock()){
S3FS_PRN_ERR("Multipart Upload has not started yet.");
return false;
}
list.clear();
for(auto iter = upload_list.cbegin(); iter != upload_list.cend(); ++iter){
if(iter->petag){
list.push_back(*(iter->petag));
}else{
S3FS_PRN_ERR("The pointer to the etag string is null(internal error).");
return false;
}
}
return !list.empty();
}
// [NOTE]
// This method adds a part for a multipart upload.
// The added new part must be an area that is exactly continuous with the
// immediately preceding part.
// An error will occur if it is discontinuous or if it overlaps with an
// existing area.
//
bool PseudoFdInfo::AppendUploadPart(off_t start, off_t size, bool is_copy, etagpair** ppetag)
{
const std::lock_guard<std::mutex> lock(upload_list_lock);
if(!IsUploadingHasLock()){
S3FS_PRN_ERR("Multipart Upload has not started yet.");
return false;
}
off_t next_start_pos = 0;
if(!upload_list.empty()){
next_start_pos = upload_list.back().startpos + upload_list.back().size;
}
if(start != next_start_pos){
S3FS_PRN_ERR("The expected starting position for the next part is %lld, but %lld was specified.", static_cast<long long int>(next_start_pos), static_cast<long long int>(start));
return false;
}
// make part number
int partnumber = static_cast<int>(upload_list.size()) + 1;
// add new part
etagpair* petag_entity = etag_entities.add(etagpair(nullptr, partnumber)); // [NOTE] Create the etag entity and register it in the list.
upload_list.emplace_back(false, physical_fd, start, size, is_copy, petag_entity);
// set etag pointer
if(ppetag){
*ppetag = petag_entity;
}
return true;
}
//
// Utility for sorting upload list
//
static bool filepart_partnum_compare(const filepart& src1, const filepart& src2)
{
return src1.get_part_number() < src2.get_part_number();
}
bool PseudoFdInfo::InsertUploadPart(off_t start, off_t size, int part_num, bool is_copy, etagpair** ppetag)
{
const std::lock_guard<std::mutex> lock(upload_list_lock);
//S3FS_PRN_DBG("[start=%lld][size=%lld][part_num=%d][is_copy=%s]", static_cast<long long int>(start), static_cast<long long int>(size), part_num, (is_copy ? "true" : "false"));
if(!IsUploadingHasLock()){
S3FS_PRN_ERR("Multipart Upload has not started yet.");
return false;
}
if(start < 0 || size <= 0 || part_num < 0 || !ppetag){
S3FS_PRN_ERR("Parameters are wrong.");
return false;
}
// insert new part
etagpair* petag_entity = etag_entities.add(etagpair(nullptr, part_num));
upload_list.emplace_back(false, physical_fd, start, size, is_copy, petag_entity);
// sort by part number
std::sort(upload_list.begin(), upload_list.end(), filepart_partnum_compare);
// set etag pointer
*ppetag = petag_entity;
return true;
}
bool PseudoFdInfo::ParallelMultipartUpload(const char* path, const mp_part_list_t& mplist, bool is_copy)
{
//S3FS_PRN_DBG("[path=%s][mplist(%zu)]", SAFESTRPTR(path), mplist.size());
if(mplist.empty()){
// nothing to do
return true;
}
if(!OpenUploadFd()){
return false;
}
// Get upload id/fd before loop
std::string tmp_upload_id;
int tmp_upload_fd = -1;
if(!GetUploadInfo(tmp_upload_id, tmp_upload_fd)){
return false;
}
std::string strpath = SAFESTRPTR(path);
for(auto iter = mplist.cbegin(); iter != mplist.cend(); ++iter){
// Insert upload part
etagpair* petag = nullptr;
if(!InsertUploadPart(iter->start, iter->size, iter->part_num, is_copy, &petag)){
S3FS_PRN_ERR("Failed to insert Multipart Upload Part to mplist [path=%s][start=%lld][size=%lld][part_num=%d][is_copy=%s]", strpath.c_str(), static_cast<long long int>(iter->start), static_cast<long long int>(iter->size), iter->part_num, (is_copy ? "true" : "false"));
return false;
}
// setup instruction and request on another thread
int result;
if(0 != (result = multipart_upload_part_request(strpath, tmp_upload_fd, iter->start, iter->size, iter->part_num, tmp_upload_id, petag, is_copy, &uploaded_sem, &upload_list_lock, &last_result))){
S3FS_PRN_ERR("failed setup instruction for Multipart Upload Part Request by error(%d) [path=%s][start=%lld][size=%lld][part_num=%d][is_copy=%s]", result, strpath.c_str(), static_cast<long long int>(iter->start), static_cast<long long int>(iter->size), iter->part_num, (is_copy ? "true" : "false"));
return false;
}
// Count up the number of internally managed threads
IncreaseInstructionCount();
}
return true;
}
bool PseudoFdInfo::ParallelMultipartUploadAll(const char* path, const mp_part_list_t& to_upload_list, const mp_part_list_t& copy_list, int& result)
{
S3FS_PRN_DBG("[path=%s][to_upload_list(%zu)][copy_list(%zu)]", SAFESTRPTR(path), to_upload_list.size(), copy_list.size());
result = 0;
if(!OpenUploadFd()){
return false;
}
if(!ParallelMultipartUpload(path, to_upload_list, false) || !ParallelMultipartUpload(path, copy_list, true)){
S3FS_PRN_ERR("Failed setup instruction for uploading(path=%s, to_upload_list=%zu, copy_list=%zu).", SAFESTRPTR(path), to_upload_list.size(), copy_list.size());
return false;
}
// Wait for all thread exiting
result = WaitAllThreadsExit();
return true;
}
//
// Common method that calls S3fsCurl::PreMultipartUploadRequest via pre_multipart_upload_request
//
// [NOTE]
// If the request is successful, initialize upload_id.
//
int PseudoFdInfo::PreMultipartUploadRequest(const std::string& strpath, const headers_t& meta)
{
// get upload_id
std::string new_upload_id;
int result;
if(0 != (result = pre_multipart_upload_request(strpath, meta, new_upload_id))){
return result;
}
// reset upload_id
if(!RowInitialUploadInfo(new_upload_id, false/* not need to cancel */)){
S3FS_PRN_ERR("failed to setup multipart upload(set upload id to object)");
return -EIO;
}
S3FS_PRN_DBG("succeed to setup multipart upload(set upload id to object)");
return 0;
}
//
// Upload the last updated Untreated area
//
// [Overview]
// Uploads untreated areas with the maximum multipart upload size as the
// boundary.
//
// * The starting position of the untreated area is aligned with the maximum
// multipart upload size as the boundary.
// * If there is an uploaded area that overlaps with the aligned untreated
// area, that uploaded area is canceled and absorbed by the untreated area.
// * Upload only when the aligned untreated area exceeds the maximum multipart
// upload size.
// * When the start position of the untreated area is changed to boundary
// alignment(to backward), and if that gap area is remained, that area is
// rest to untreated area.
//
ssize_t PseudoFdInfo::UploadBoundaryLastUntreatedArea(const char* path, headers_t& meta, FdEntity* pfdent)
{
S3FS_PRN_DBG("[path=%s][pseudo_fd=%d][physical_fd=%d]", SAFESTRPTR(path), pseudo_fd, physical_fd);
if(!path || -1 == physical_fd || -1 == pseudo_fd || !pfdent){
S3FS_PRN_ERR("pseudo_fd(%d) to physical_fd(%d) for path(%s) is not opened or not writable, or pfdent is nullptr.", pseudo_fd, physical_fd, path);
return -EBADF;
}
//
// Get last update untreated area
//
off_t last_untreated_start = 0;
off_t last_untreated_size = 0;
if(!pfdent->GetLastUpdateUntreatedPart(last_untreated_start, last_untreated_size) || last_untreated_start < 0 || last_untreated_size <= 0){
S3FS_PRN_WARN("Not found last update untreated area or it is empty, thus return without any error.");
return 0;
}
//
// Aligns the start position of the last updated raw area with the boundary
//
// * Align the last updated raw space with the maximum upload size boundary.
// * The remaining size of the part before the boundary is will not be uploaded.
//
off_t max_mp_size = S3fsCurl::GetMultipartSize();
off_t aligned_start = ((last_untreated_start / max_mp_size) + (0 < (last_untreated_start % max_mp_size) ? 1 : 0)) * max_mp_size;
if((last_untreated_start + last_untreated_size) <= aligned_start){
S3FS_PRN_INFO("After the untreated area(start=%lld, size=%lld) is aligned with the boundary, the aligned start(%lld) exceeds the untreated area, so there is nothing to do.", static_cast<long long int>(last_untreated_start), static_cast<long long int>(last_untreated_size), static_cast<long long int>(aligned_start));
return 0;
}
off_t aligned_size = (((last_untreated_start + last_untreated_size) - aligned_start) / max_mp_size) * max_mp_size;
if(0 == aligned_size){
S3FS_PRN_DBG("After the untreated area(start=%lld, size=%lld) is aligned with the boundary(start is %lld), the aligned size is empty, so nothing to do.", static_cast<long long int>(last_untreated_start), static_cast<long long int>(last_untreated_size), static_cast<long long int>(aligned_start));
return 0;
}
off_t front_rem_start = last_untreated_start; // start of the remainder untreated area in front of the boundary
off_t front_rem_size = aligned_start - last_untreated_start; // size of the remainder untreated area in front of the boundary
//
// Get the area for uploading, if last update treated area can be uploaded.
//
// [NOTE]
// * Create the upload area list, if the untreated area aligned with the boundary
// exceeds the maximum upload size.
// * If it overlaps with an area that has already been uploaded(unloaded list),
// that area is added to the cancellation list and included in the untreated area.
//
mp_part_list_t to_upload_list;
filepart_list_t cancel_uploaded_list;
if(!ExtractUploadPartsFromUntreatedArea(aligned_start, aligned_size, to_upload_list, cancel_uploaded_list, S3fsCurl::GetMultipartSize())){
S3FS_PRN_ERR("Failed to extract upload parts from last untreated area.");
return -EIO;
}
if(to_upload_list.empty()){
S3FS_PRN_INFO("There is nothing to upload. In most cases, the untreated area does not meet the upload size.");
return 0;
}
//
// Has multipart uploading already started?
//
if(!IsUploading()){
std::string strpath = SAFESTRPTR(path);
int result;
if(0 != (result = PreMultipartUploadRequest(strpath, meta))){
return result;
}
}
//
// Output debug level information
//
// When canceling(overwriting) a part that has already been uploaded, output it.
//
if(S3fsLog::IsS3fsLogDbg()){
for(auto cancel_iter = cancel_uploaded_list.cbegin(); cancel_iter != cancel_uploaded_list.cend(); ++cancel_iter){
S3FS_PRN_DBG("Cancel uploaded: start(%lld), size(%lld), part number(%d)", static_cast<long long int>(cancel_iter->startpos), static_cast<long long int>(cancel_iter->size), (cancel_iter->petag ? cancel_iter->petag->part_num : -1));
}
}
//
// Upload Multipart parts
//
if(!ParallelMultipartUpload(path, to_upload_list, false)){
S3FS_PRN_ERR("Failed to upload multipart parts.");
return -EIO;
}
//
// Exclude the uploaded Untreated area and update the last Untreated area.
//
off_t behind_rem_start = aligned_start + aligned_size;
off_t behind_rem_size = (last_untreated_start + last_untreated_size) - behind_rem_start;
if(!pfdent->ReplaceLastUpdateUntreatedPart(front_rem_start, front_rem_size, behind_rem_start, behind_rem_size)){
S3FS_PRN_WARN("The last untreated area could not be detected and the uploaded area could not be excluded from it, but continue because it does not affect the overall processing.");
}
return 0;
}
int PseudoFdInfo::WaitAllThreadsExit()
{
int result;
bool is_loop = true;
{
const std::lock_guard<std::mutex> lock(upload_list_lock);
if(0 == instruct_count){
result = last_result;
is_loop = false;
}
}
while(is_loop){
// need to wait the worker exiting
uploaded_sem.acquire();
{
const std::lock_guard<std::mutex> lock(upload_list_lock);
if(0 == --instruct_count){
// break loop
result = last_result;
is_loop = false;
}
}
}
return result;
}
bool PseudoFdInfo::CancelAllThreads()
{
bool need_cancel = false;
{
const std::lock_guard<std::mutex> lock(upload_list_lock);
if(0 < instruct_count){
S3FS_PRN_INFO("The upload thread is running, so cancel them and wait for the end.");
need_cancel = true;
last_result = -ECANCELED; // to stop thread running
}
}
if(need_cancel){
WaitAllThreadsExit();
}
return true;
}
//
// Extract the list for multipart upload from the Untreated Area
//
// The untreated_start parameter must be set aligning it with the boundaries
// of the maximum multipart upload size. This method expects it to be bounded.
//
// This method creates the upload area aligned from the untreated area by
// maximum size and creates the required list.
// If it overlaps with an area that has already been uploaded, the overlapped
// upload area will be canceled and absorbed by the untreated area.
// If the list creation process is complete and areas smaller than the maximum
// size remain, those area will be reset to untreated_start and untreated_size
// and returned to the caller.
// If the called untreated area is smaller than the maximum size of the
// multipart upload, no list will be created.
//
// [NOTE]
// Maximum multipart upload size must be uploading boundary.
//
bool PseudoFdInfo::ExtractUploadPartsFromUntreatedArea(off_t untreated_start, off_t untreated_size, mp_part_list_t& to_upload_list, filepart_list_t& cancel_upload_list, off_t max_mp_size)
{
if(untreated_start < 0 || untreated_size <= 0){
S3FS_PRN_ERR("Parameters are wrong(untreated_start=%lld, untreated_size=%lld).", static_cast<long long int>(untreated_start), static_cast<long long int>(untreated_size));
return false;
}
// Initialize lists
to_upload_list.clear();
cancel_upload_list.clear();
//
// Align start position with maximum multipart upload boundaries
//
off_t aligned_start = (untreated_start / max_mp_size) * max_mp_size;
off_t aligned_size = untreated_size + (untreated_start - aligned_start);
//
// Check aligned untreated size
//
if(aligned_size < max_mp_size){
S3FS_PRN_INFO("untreated area(start=%lld, size=%lld) to aligned boundary(start=%lld, size=%lld) is smaller than max mp size(%lld), so nothing to do.", static_cast<long long int>(untreated_start), static_cast<long long int>(untreated_size), static_cast<long long int>(aligned_start), static_cast<long long int>(aligned_size), static_cast<long long int>(max_mp_size));
return true; // successful termination
}
//
// Check each unloaded area in list
//
// [NOTE]
// The uploaded area must be to be aligned by boundary.
// Also, it is assumed that it must not be a copy area.
// So if the areas overlap, include uploaded area as an untreated area.
//
{
const std::lock_guard<std::mutex> lock(upload_list_lock);
for(auto cur_iter = upload_list.begin(); cur_iter != upload_list.end(); /* ++cur_iter */){
// Check overlap
if((cur_iter->startpos + cur_iter->size - 1) < aligned_start || (aligned_start + aligned_size - 1) < cur_iter->startpos){
// Areas do not overlap
++cur_iter;
}else{
// The areas overlap
//
// Since the start position of the uploaded area is aligned with the boundary,
// it is not necessary to check the start position.
// If the uploaded area exceeds the untreated area, expand the untreated area.
//
if((aligned_start + aligned_size - 1) < (cur_iter->startpos + cur_iter->size - 1)){
aligned_size += (cur_iter->startpos + cur_iter->size) - (aligned_start + aligned_size);
}
//
// Add this to cancel list
//
cancel_upload_list.push_back(*cur_iter); // Copy and Push to cancel list
cur_iter = upload_list.erase(cur_iter);
}
}
}
//
// Add upload area to the list
//
while(max_mp_size <= aligned_size){
int part_num = static_cast<int>((aligned_start / max_mp_size) + 1);
to_upload_list.emplace_back(aligned_start, max_mp_size, part_num);
aligned_start += max_mp_size;
aligned_size -= max_mp_size;
}
return true;
}
//
// Extract the area lists to be uploaded/downloaded for the entire file.
//
// [Parameters]
// to_upload_list : A list of areas to upload in multipart upload.
// to_copy_list : A list of areas for copy upload in multipart upload.
// to_download_list : A list of areas that must be downloaded before multipart upload.
// cancel_upload_list : A list of areas that have already been uploaded and will be canceled(overwritten).
// wait_upload_complete : If cancellation areas exist, this flag is set to true when it is necessary to wait until the upload of those cancellation areas is complete.
// file_size : The size of the upload file.
// use_copy : Specify true if copy multipart upload is available.
//
// [NOTE]
// The untreated_list in fdentity does not change, but upload_list is changed.
// (If you want to restore it, you can use cancel_upload_list.)
//
bool PseudoFdInfo::ExtractUploadPartsFromAllArea(UntreatedParts& untreated_list, mp_part_list_t& to_upload_list, mp_part_list_t& to_copy_list, mp_part_list_t& to_download_list, filepart_list_t& cancel_upload_list, bool& wait_upload_complete, off_t max_mp_size, off_t file_size, bool use_copy)
{
const std::lock_guard<std::mutex> lock(upload_list_lock);
// Initialize lists
to_upload_list.clear();
to_copy_list.clear();
to_download_list.clear();
cancel_upload_list.clear();
wait_upload_complete = false;
// Duplicate untreated list
untreated_list_t dup_untreated_list;
untreated_list.Duplicate(dup_untreated_list);
// Initialize the iterator of each list first
auto dup_untreated_iter = dup_untreated_list.begin();
auto uploaded_iter = upload_list.begin();
//
// Loop to extract areas to upload and download
//
// Check at the boundary of the maximum upload size from the beginning of the file
//
for(off_t cur_start = 0, cur_size = 0; cur_start < file_size; cur_start += cur_size){
//
// Set part size
// (To avoid confusion, the area to be checked is called the "current area".)
//
cur_size = ((cur_start + max_mp_size) <= file_size ? max_mp_size : (file_size - cur_start));
//
// Extract the untreated area that overlaps this current area.
// (The extracted area is deleted from dup_untreated_list.)
//
untreated_list_t cur_untreated_list;
for(cur_untreated_list.clear(); dup_untreated_iter != dup_untreated_list.end(); ){
if((dup_untreated_iter->start < (cur_start + cur_size)) && (cur_start < (dup_untreated_iter->start + dup_untreated_iter->size))){
// this untreated area is overlap
off_t tmp_untreated_start;
off_t tmp_untreated_size;
if(dup_untreated_iter->start < cur_start){
// [NOTE]
// This untreated area overlaps with the current area, but starts
// in front of the target area.
// This state should not be possible, but if this state is detected,
// the part before the target area will be deleted.
//
tmp_untreated_start = cur_start;
tmp_untreated_size = dup_untreated_iter->size - (cur_start - dup_untreated_iter->start);
}else{
tmp_untreated_start = dup_untreated_iter->start;
tmp_untreated_size = dup_untreated_iter->size;
}
//
// Check the end of the overlapping untreated area.
//
if((tmp_untreated_start + tmp_untreated_size) <= (cur_start + cur_size)){
//
// All of untreated areas are within the current area
//
// - Add this untreated area to cur_untreated_list
// - Delete this from dup_untreated_list
//
cur_untreated_list.emplace_back(tmp_untreated_start, tmp_untreated_size);
dup_untreated_iter = dup_untreated_list.erase(dup_untreated_iter);
}else{
//
// The untreated area exceeds the end of the current area
//
// Adjust untreated area
tmp_untreated_size = (cur_start + cur_size) - tmp_untreated_start;
// Add adjusted untreated area to cur_untreated_list
cur_untreated_list.emplace_back(tmp_untreated_start, tmp_untreated_size);
// Remove this adjusted untreated area from the area pointed
// to by dup_untreated_iter.
dup_untreated_iter->size = (dup_untreated_iter->start + dup_untreated_iter->size) - (cur_start + cur_size);
dup_untreated_iter->start = tmp_untreated_start + tmp_untreated_size;
}
}else if((cur_start + cur_size - 1) < dup_untreated_iter->start){
// this untreated area is over the current area, thus break loop.
break;
}else{
++dup_untreated_iter;
}
}
//
// Check uploaded area
//
// [NOTE]
// The uploaded area should be aligned with the maximum upload size boundary.
// It also assumes that each size of uploaded area must be a maximum upload
// size.
//
auto overlap_uploaded_iter = upload_list.end();
for(; uploaded_iter != upload_list.end(); ++uploaded_iter){
if((cur_start < (uploaded_iter->startpos + uploaded_iter->size)) && (uploaded_iter->startpos < (cur_start + cur_size))){
if(overlap_uploaded_iter != upload_list.end()){
//
// Something wrong in this unloaded area.
//
// This area is not aligned with the boundary, then this condition
// is unrecoverable and return failure.
//
S3FS_PRN_ERR("The uploaded list may not be the boundary for the maximum multipart upload size. No further processing is possible.");
return false;
}
// Set this iterator to overlap iter
overlap_uploaded_iter = uploaded_iter;
}else if((cur_start + cur_size - 1) < uploaded_iter->startpos){
break;
}
}
//
// Create upload/download/cancel/copy list for this current area
//
int part_num = static_cast<int>((cur_start / max_mp_size) + 1);
if(cur_untreated_list.empty()){
//
// No untreated area was detected in this current area
//
if(overlap_uploaded_iter != upload_list.end()){
//
// This current area already uploaded, then nothing to add to lists.
//
S3FS_PRN_DBG("Already uploaded: start=%lld, size=%lld", static_cast<long long int>(cur_start), static_cast<long long int>(cur_size));
}else{
//
// This current area has not been uploaded
// (neither an uploaded area nor an untreated area.)
//
if(use_copy){
//
// Copy multipart upload available
//
S3FS_PRN_DBG("To copy: start=%lld, size=%lld", static_cast<long long int>(cur_start), static_cast<long long int>(cur_size));
to_copy_list.emplace_back(cur_start, cur_size, part_num);
}else{
//
// This current area needs to be downloaded and uploaded
//
S3FS_PRN_DBG("To download and upload: start=%lld, size=%lld", static_cast<long long int>(cur_start), static_cast<long long int>(cur_size));
to_download_list.emplace_back(cur_start, cur_size);
to_upload_list.emplace_back(cur_start, cur_size, part_num);
}
}
}else{
//
// Found untreated area in this current area
//
if(overlap_uploaded_iter != upload_list.end()){
//
// This current area is also the uploaded area
//
// [NOTE]
// The uploaded area is aligned with boundary, there are all data in
// this current area locally(which includes all data of untreated area).
// So this current area only needs to be uploaded again.
//
S3FS_PRN_DBG("Cancel upload: start=%lld, size=%lld", static_cast<long long int>(overlap_uploaded_iter->startpos), static_cast<long long int>(overlap_uploaded_iter->size));
if(!overlap_uploaded_iter->uploaded){
S3FS_PRN_DBG("This cancel upload area is still uploading, so you must wait for it to complete before starting any Stream uploads.");
wait_upload_complete = true;
}
cancel_upload_list.push_back(*overlap_uploaded_iter); // add this uploaded area to cancel_upload_list
uploaded_iter = upload_list.erase(overlap_uploaded_iter); // remove it from upload_list
S3FS_PRN_DBG("To upload: start=%lld, size=%lld", static_cast<long long int>(cur_start), static_cast<long long int>(cur_size));
to_upload_list.emplace_back(cur_start, cur_size, part_num); // add new uploading area to list
}else{
//
// No uploaded area overlap this current area
// (Areas other than the untreated area must be downloaded.)
//
// [NOTE]
// Need to consider the case where there is a gap between the start
// of the current area and the untreated area.
// This gap is the area that should normally be downloaded.
// But it is the area that can be copied if we can use copy multipart
// upload. Then If we can use copy multipart upload and the previous
// area is used copy multipart upload, this gap will be absorbed by
// the previous area.
// Unifying the copy multipart upload area can reduce the number of
// upload requests.
//
off_t tmp_cur_start = cur_start;
off_t tmp_cur_size = cur_size;
off_t changed_start = cur_start;
off_t changed_size = cur_size;
bool first_area = true;
for(auto tmp_cur_untreated_iter = cur_untreated_list.cbegin(); tmp_cur_untreated_iter != cur_untreated_list.cend(); ++tmp_cur_untreated_iter, first_area = false){
if(tmp_cur_start < tmp_cur_untreated_iter->start){
//
// Detected a gap at the start of area
//
bool include_prev_copy_part = false;
if(first_area && use_copy && !to_copy_list.empty()){
//
// Make sure that the area of the last item in to_copy_list
// is contiguous with this current area.
//
// [NOTE]
// Areas can be unified if the total size of the areas is
// within 5GB and the remaining area after unification is
// larger than the minimum multipart upload size.
//
auto copy_riter = to_copy_list.rbegin();
if( (copy_riter->start + copy_riter->size) == tmp_cur_start &&
(copy_riter->size + (tmp_cur_untreated_iter->start - tmp_cur_start)) <= FIVE_GB &&
((tmp_cur_start + tmp_cur_size) - tmp_cur_untreated_iter->start) >= MIN_MULTIPART_SIZE )
{
//
// Unify to this area to previous copy area.
//
copy_riter->size += tmp_cur_untreated_iter->start - tmp_cur_start;
S3FS_PRN_DBG("Resize to copy: start=%lld, size=%lld", static_cast<long long int>(copy_riter->start), static_cast<long long int>(copy_riter->size));
changed_size -= (tmp_cur_untreated_iter->start - changed_start);
changed_start = tmp_cur_untreated_iter->start;
include_prev_copy_part = true;
}
}
if(!include_prev_copy_part){
//
// If this area is not unified, need to download this area
//
S3FS_PRN_DBG("To download: start=%lld, size=%lld", static_cast<long long int>(tmp_cur_start), static_cast<long long int>(tmp_cur_untreated_iter->start - tmp_cur_start));
to_download_list.emplace_back(tmp_cur_start, tmp_cur_untreated_iter->start - tmp_cur_start);
}
}
//
// Set next start position
//
tmp_cur_size = (tmp_cur_start + tmp_cur_size) - (tmp_cur_untreated_iter->start + tmp_cur_untreated_iter->size);
tmp_cur_start = tmp_cur_untreated_iter->start + tmp_cur_untreated_iter->size;
}
//
// Add download area to list, if remaining size
//
if(0 < tmp_cur_size){
S3FS_PRN_DBG("To download: start=%lld, size=%lld", static_cast<long long int>(tmp_cur_start), static_cast<long long int>(tmp_cur_size));
to_download_list.emplace_back(tmp_cur_start, tmp_cur_size);
}
//
// Set upload area(whole of area) to list
//
S3FS_PRN_DBG("To upload: start=%lld, size=%lld", static_cast<long long int>(changed_start), static_cast<long long int>(changed_size));
to_upload_list.emplace_back(changed_start, changed_size, part_num);
}
}
}
return true;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

111
src/fdcache_fdinfo.h Normal file
View File

@ -0,0 +1,111 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_FDCACHE_FDINFO_H_
#define S3FS_FDCACHE_FDINFO_H_
#include <memory>
#include <mutex>
#include <string>
#include "common.h"
#include "fdcache_entity.h"
#include "psemaphore.h"
#include "metaheader.h"
#include "types.h"
class UntreatedParts;
//------------------------------------------------
// Class PseudoFdInfo
//------------------------------------------------
class PseudoFdInfo
{
private:
int pseudo_fd;
int physical_fd;
int flags; // flags at open
mutable std::mutex upload_list_lock; // protects upload_id/fd, upload_list, etc.
std::string upload_id GUARDED_BY(upload_list_lock); //
int upload_fd GUARDED_BY(upload_list_lock); // duplicated fd for uploading
filepart_list_t upload_list GUARDED_BY(upload_list_lock);
petagpool etag_entities GUARDED_BY(upload_list_lock); // list of etag string and part number entities(to maintain the etag entity even if MPPART_INFO is destroyed)
int instruct_count GUARDED_BY(upload_list_lock); // number of instructions for processing by threads
int last_result GUARDED_BY(upload_list_lock); // the result of thread processing
Semaphore uploaded_sem; // use a semaphore to trigger an upload completion like event flag
private:
bool Clear();
void CloseUploadFd();
bool OpenUploadFd();
bool ResetUploadInfo() REQUIRES(upload_list_lock);
bool RowInitialUploadInfo(const std::string& id, bool is_cancel_mp);
void IncreaseInstructionCount();
bool GetUploadInfo(std::string& id, int& fd) const;
bool ParallelMultipartUpload(const char* path, const mp_part_list_t& mplist, bool is_copy);
bool InsertUploadPart(off_t start, off_t size, int part_num, bool is_copy, etagpair** ppetag);
bool CancelAllThreads();
bool ExtractUploadPartsFromUntreatedArea(off_t untreated_start, off_t untreated_size, mp_part_list_t& to_upload_list, filepart_list_t& cancel_upload_list, off_t max_mp_size);
bool IsUploadingHasLock() const REQUIRES(upload_list_lock);
public:
explicit PseudoFdInfo(int fd = -1, int open_flags = 0);
~PseudoFdInfo();
PseudoFdInfo(const PseudoFdInfo&) = delete;
PseudoFdInfo(PseudoFdInfo&&) = delete;
PseudoFdInfo& operator=(const PseudoFdInfo&) = delete;
PseudoFdInfo& operator=(PseudoFdInfo&&) = delete;
int GetPhysicalFd() const { return physical_fd; }
int GetPseudoFd() const { return pseudo_fd; }
int GetFlags() const { return flags; }
bool Writable() const;
bool Readable() const;
bool Set(int fd, int open_flags);
bool ClearUploadInfo(bool is_cancel_mp = false);
bool InitialUploadInfo(const std::string& id){ return RowInitialUploadInfo(id, true); }
bool IsUploading() const;
bool GetUploadId(std::string& id) const;
bool GetEtaglist(etaglist_t& list) const;
bool AppendUploadPart(off_t start, off_t size, bool is_copy = false, etagpair** ppetag = nullptr);
bool ParallelMultipartUploadAll(const char* path, const mp_part_list_t& to_upload_list, const mp_part_list_t& copy_list, int& result);
int PreMultipartUploadRequest(const std::string& strpath, const headers_t& meta);
int WaitAllThreadsExit();
ssize_t UploadBoundaryLastUntreatedArea(const char* path, headers_t& meta, FdEntity* pfdent) REQUIRES(pfdent->GetMutex());
bool ExtractUploadPartsFromAllArea(UntreatedParts& untreated_list, mp_part_list_t& to_upload_list, mp_part_list_t& to_copy_list, mp_part_list_t& to_download_list, filepart_list_t& cancel_upload_list, bool& wait_upload_complete, off_t max_mp_size, off_t file_size, bool use_copy);
};
typedef std::map<int, std::unique_ptr<PseudoFdInfo>> fdinfo_map_t;
#endif // S3FS_FDCACHE_FDINFO_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

1032
src/fdcache_page.cpp Normal file

File diff suppressed because it is too large Load Diff

140
src/fdcache_page.h Normal file
View File

@ -0,0 +1,140 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_FDCACHE_PAGE_H_
#define S3FS_FDCACHE_PAGE_H_
#include <cstdint>
#include <sys/types.h>
#include <vector>
//------------------------------------------------
// Symbols
//------------------------------------------------
// [NOTE]
// If the following symbols in lseek whence are undefined, define them.
// If it is not supported by lseek, s3fs judges by the processing result of lseek.
//
#ifndef SEEK_DATA
#define SEEK_DATA 3
#endif
#ifndef SEEK_HOLE
#define SEEK_HOLE 4
#endif
//------------------------------------------------
// Structure fdpage
//------------------------------------------------
// page block information
struct fdpage
{
off_t offset;
off_t bytes;
bool loaded;
bool modified;
explicit fdpage(off_t start = 0, off_t size = 0, bool is_loaded = false, bool is_modified = false) :
offset(start), bytes(size), loaded(is_loaded), modified(is_modified) {}
off_t next() const
{
return (offset + bytes);
}
off_t end() const
{
return (0 < bytes ? offset + bytes - 1 : 0);
}
};
typedef std::vector<struct fdpage> fdpage_list_t;
//------------------------------------------------
// Class PageList
//------------------------------------------------
class CacheFileStat;
class FdEntity;
// cppcheck-suppress copyCtorAndEqOperator
class PageList
{
friend class FdEntity; // only one method access directly pages.
private:
fdpage_list_t pages;
bool is_shrink; // [NOTE] true if it has been shrunk even once
public:
enum class page_status : int8_t {
NOT_LOAD_MODIFIED = 0,
LOADED,
MODIFIED,
LOAD_MODIFIED
};
private:
static bool GetSparseFilePages(int fd, size_t file_size, fdpage_list_t& sparse_list);
static bool CheckZeroAreaInFile(int fd, off_t start, size_t bytes);
static bool CheckAreaInSparseFile(const struct fdpage& checkpage, const fdpage_list_t& sparse_list, int fd, fdpage_list_t& err_area_list, fdpage_list_t& warn_area_list);
void Clear();
bool Parse(off_t new_pos);
bool Serialize(const CacheFileStat& file, ino_t inode) const;
public:
static void FreeList(fdpage_list_t& list);
explicit PageList(off_t size = 0, bool is_loaded = false, bool is_modified = false, bool shrunk = false);
PageList(const PageList&) = delete;
PageList(PageList&&) = delete;
PageList& operator=(const PageList&) = delete;
PageList& operator=(PageList&&) = delete;
~PageList();
bool Init(off_t size, bool is_loaded, bool is_modified);
off_t Size() const;
bool Resize(off_t size, bool is_loaded, bool is_modified);
bool IsPageLoaded(off_t start = 0, off_t size = 0) const; // size=0 is checking to end of list
bool SetPageLoadedStatus(off_t start, off_t size, PageList::page_status pstatus = page_status::LOADED, bool is_compress = true);
bool FindUnloadedPage(off_t start, off_t& resstart, off_t& ressize) const;
off_t GetTotalUnloadedPageSize(off_t start = 0, off_t size = 0, off_t limit_size = 0) const; // size=0 is checking to end of list
size_t GetUnloadedPages(fdpage_list_t& unloaded_list, off_t start = 0, off_t size = 0) const; // size=0 is checking to end of list
bool GetPageListsForMultipartUpload(fdpage_list_t& dlpages, fdpage_list_t& mixuppages, off_t max_partsize);
bool GetNoDataPageLists(fdpage_list_t& nodata_pages, off_t start = 0, size_t size = 0);
off_t BytesModified() const;
bool IsModified() const;
bool ClearAllModified();
bool Compress();
bool Deserialize(CacheFileStat& file, ino_t inode);
void Dump() const;
bool CompareSparseFile(int fd, size_t file_size, fdpage_list_t& err_area_list, fdpage_list_t& warn_area_list) const;
};
#endif // S3FS_FDCACHE_PAGE_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

105
src/fdcache_pseudofd.cpp Normal file
View File

@ -0,0 +1,105 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Takeshi Nakatani <ggtakec.com>
*
* 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.
*/
#include <algorithm>
#include <cstdlib>
#include <mutex>
#include <vector>
#include "fdcache_pseudofd.h"
//------------------------------------------------
// Symbols
//------------------------------------------------
// [NOTE]
// The minimum pseudo fd value starts 2.
// This is to avoid mistakes for 0(stdout) and 1(stderr), which are usually used.
//
static constexpr int MIN_PSEUDOFD_NUMBER = 2;
//------------------------------------------------
// PseudoFdManager class methods
//------------------------------------------------
PseudoFdManager& PseudoFdManager::GetManager()
{
static PseudoFdManager singleton;
return singleton;
}
int PseudoFdManager::Get()
{
return (PseudoFdManager::GetManager()).CreatePseudoFd();
}
bool PseudoFdManager::Release(int fd)
{
return (PseudoFdManager::GetManager()).ReleasePseudoFd(fd);
}
//------------------------------------------------
// PseudoFdManager methods
//------------------------------------------------
int PseudoFdManager::GetUnusedMinPseudoFd() const
{
int min_fd = MIN_PSEUDOFD_NUMBER;
// Look for the first discontinuous value.
for(auto iter = pseudofd_list.cbegin(); iter != pseudofd_list.cend(); ++iter){
if(min_fd == (*iter)){
++min_fd;
}else if(min_fd < (*iter)){
break;
}
}
return min_fd;
}
int PseudoFdManager::CreatePseudoFd()
{
const std::lock_guard<std::mutex> lock(pseudofd_list_lock);
int new_fd = PseudoFdManager::GetUnusedMinPseudoFd();
pseudofd_list.push_back(new_fd);
std::sort(pseudofd_list.begin(), pseudofd_list.end());
return new_fd;
}
bool PseudoFdManager::ReleasePseudoFd(int fd)
{
const std::lock_guard<std::mutex> lock(pseudofd_list_lock);
for(auto iter = pseudofd_list.begin(); iter != pseudofd_list.end(); ++iter){
if(fd == (*iter)){
pseudofd_list.erase(iter);
return true;
}
}
return false;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

73
src/fdcache_pseudofd.h Normal file
View File

@ -0,0 +1,73 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_FDCACHE_PSEUDOFD_H_
#define S3FS_FDCACHE_PSEUDOFD_H_
#include <mutex>
#include <vector>
#include "common.h"
//------------------------------------------------
// Typdefs
//------------------------------------------------
// List of pseudo fd in use
//
typedef std::vector<int> pseudofd_list_t;
//------------------------------------------------
// Class PseudoFdManager
//------------------------------------------------
class PseudoFdManager
{
private:
pseudofd_list_t pseudofd_list GUARDED_BY(pseudofd_list_lock);
std::mutex pseudofd_list_lock; // protects pseudofd_list
static PseudoFdManager& GetManager();
PseudoFdManager() = default;
~PseudoFdManager() = default;
int GetUnusedMinPseudoFd() const REQUIRES(pseudofd_list_lock);
int CreatePseudoFd();
bool ReleasePseudoFd(int fd);
public:
PseudoFdManager(const PseudoFdManager&) = delete;
PseudoFdManager(PseudoFdManager&&) = delete;
PseudoFdManager& operator=(const PseudoFdManager&) = delete;
PseudoFdManager& operator=(PseudoFdManager&&) = delete;
static int Get();
static bool Release(int fd);
};
#endif // S3FS_FDCACHE_PSEUDOFD_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

326
src/fdcache_stat.cpp Normal file
View File

@ -0,0 +1,326 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Takeshi Nakatani <ggtakec.com>
*
* 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.
*/
#include <cerrno>
#include <unistd.h>
#include <string>
#include <sys/file.h>
#include <sys/stat.h>
#include "s3fs_logger.h"
#include "fdcache_stat.h"
#include "fdcache.h"
#include "s3fs_util.h"
#include "s3fs_cred.h"
#include "string_util.h"
//------------------------------------------------
// CacheFileStat class methods
//------------------------------------------------
std::string CacheFileStat::GetCacheFileStatTopDir()
{
std::string top_path;
if(!FdManager::IsCacheDir() || S3fsCred::GetBucket().empty()){
return top_path;
}
// stat top dir( "/<cache_dir>/.<bucket_name>.stat" )
top_path += FdManager::GetCacheDir();
top_path += "/.";
top_path += S3fsCred::GetBucket();
top_path += ".stat";
return top_path;
}
int CacheFileStat::MakeCacheFileStatPath(const char* path, std::string& sfile_path, bool is_create_dir)
{
std::string top_path = CacheFileStat::GetCacheFileStatTopDir();
if(top_path.empty()){
S3FS_PRN_ERR("The path to cache top dir is empty.");
return -EIO;
}
if(is_create_dir){
int result;
if(0 != (result = mkdirp(top_path + mydirname(path), 0777))){
S3FS_PRN_ERR("failed to create dir(%s) by errno(%d).", path, result);
return result;
}
}
if(!path || '\0' == path[0]){
sfile_path = top_path;
}else{
sfile_path = top_path + SAFESTRPTR(path);
}
return 0;
}
bool CacheFileStat::CheckCacheFileStatTopDir()
{
std::string top_path = CacheFileStat::GetCacheFileStatTopDir();
if(top_path.empty()){
S3FS_PRN_INFO("The path to cache top dir is empty, thus not need to check permission.");
return true;
}
return check_exist_dir_permission(top_path.c_str());
}
int CacheFileStat::DeleteCacheFileStat(const char* path)
{
if(!path || '\0' == path[0]){
return -EINVAL;
}
// stat path
std::string sfile_path;
int result;
if(0 != (result = CacheFileStat::MakeCacheFileStatPath(path, sfile_path, false))){
S3FS_PRN_ERR("failed to create cache stat file path(%s)", path);
return result;
}
if(0 != unlink(sfile_path.c_str())){
result = -errno;
if(-ENOENT == result){
S3FS_PRN_DBG("failed to delete file(%s): errno=%d", path, result);
}else{
S3FS_PRN_ERR("failed to delete file(%s): errno=%d", path, result);
}
return result;
}
return 0;
}
// [NOTE]
// If remove stat file directory, it should do before removing
// file cache directory.
//
bool CacheFileStat::DeleteCacheFileStatDirectory()
{
std::string top_path = CacheFileStat::GetCacheFileStatTopDir();
if(top_path.empty()){
S3FS_PRN_INFO("The path to cache top dir is empty, thus not need to remove it.");
return true;
}
return delete_files_in_dir(top_path.c_str(), true);
}
bool CacheFileStat::RenameCacheFileStat(const char* oldpath, const char* newpath)
{
if(!oldpath || '\0' == oldpath[0] || !newpath || '\0' == newpath[0]){
return false;
}
// stat path
std::string old_filestat;
std::string new_filestat;
if(0 != CacheFileStat::MakeCacheFileStatPath(oldpath, old_filestat, false) || 0 != CacheFileStat::MakeCacheFileStatPath(newpath, new_filestat, false)){
return false;
}
// check new stat path
struct stat st;
if(0 == stat(new_filestat.c_str(), &st)){
// new stat path is existed, then unlink it.
if(-1 == unlink(new_filestat.c_str())){
S3FS_PRN_ERR("failed to unlink new cache file stat path(%s) by errno(%d).", new_filestat.c_str(), errno);
return false;
}
}
// check old stat path
if(0 != stat(old_filestat.c_str(), &st)){
// old stat path is not existed, then nothing to do any more.
return true;
}
// link and unlink
if(-1 == link(old_filestat.c_str(), new_filestat.c_str())){
S3FS_PRN_ERR("failed to link old cache file stat path(%s) to new cache file stat path(%s) by errno(%d).", old_filestat.c_str(), new_filestat.c_str(), errno);
return false;
}
if(-1 == unlink(old_filestat.c_str())){
S3FS_PRN_ERR("failed to unlink old cache file stat path(%s) by errno(%d).", old_filestat.c_str(), errno);
return false;
}
return true;
}
//------------------------------------------------
// CacheFileStat methods
//------------------------------------------------
CacheFileStat::CacheFileStat(const char* tpath) : fd(-1)
{
if(tpath && '\0' != tpath[0]){
SetPath(tpath, true);
}
}
CacheFileStat::~CacheFileStat()
{
Release();
}
bool CacheFileStat::SetPath(const char* tpath, bool is_open)
{
if(!tpath || '\0' == tpath[0]){
return false;
}
if(!Release()){
// could not close old stat file.
return false;
}
path = tpath;
if(!is_open){
return true;
}
return Open();
}
// [NOTE]
// There is no need to check whether the file is open because using rename().
//
bool CacheFileStat::OverWriteFile(const std::string& strall) const
{
// make temporary file path(in same cache directory)
std::string sfile_path;
if(0 != CacheFileStat::MakeCacheFileStatPath(path.c_str(), sfile_path, true)){
S3FS_PRN_ERR("failed to create cache stat file path(%s)", path.c_str());
return false;
}
std::string strTmpFile = mydirname(sfile_path) + "/.tmpstat.XXXXXX";
strTmpFile.push_back('\0'); // terminate with a null character and allocate space for it.
// open temporary file(mode: 0600)
//
// [TODO]
// Currently, use "&str[pos]" to make it possible to build with C++14.
// Once we support C++17 or later, we will use "str.data()".
//
int tmpfd;
if(-1 == (tmpfd = mkstemp(&strTmpFile[0]))){ // NOLINT(readability-container-data-pointer)
S3FS_PRN_ERR("failed to create temporary cache stat file path(%s) for %s cache", strTmpFile.c_str(), sfile_path.c_str());
return false;
}
// write contents
if(0 >= pwrite(tmpfd, strall.c_str(), strall.length(), 0)){
S3FS_PRN_ERR("failed to write stats to temporary file(%d)", errno);
close(tmpfd);
return false;
}
close(tmpfd);
// rename
if(0 != rename(strTmpFile.c_str(), sfile_path.c_str())){
S3FS_PRN_ERR("failed to rename temporary cache stat file path(%s) to %s cache", strTmpFile.c_str(), sfile_path.c_str());
unlink(strTmpFile.c_str());
return false;
}
return true;
}
bool CacheFileStat::RawOpen(bool readonly)
{
if(path.empty()){
return false;
}
if(-1 != fd){
// already opened
return true;
}
// stat path
std::string sfile_path;
if(0 != CacheFileStat::MakeCacheFileStatPath(path.c_str(), sfile_path, true)){
S3FS_PRN_ERR("failed to create cache stat file path(%s)", path.c_str());
return false;
}
// open
int tmpfd;
if(readonly){
if(-1 == (tmpfd = open(sfile_path.c_str(), O_RDONLY))){
S3FS_PRN_ERR("failed to read only open cache stat file path(%s) - errno(%d)", path.c_str(), errno);
return false;
}
}else{
if(-1 == (tmpfd = open(sfile_path.c_str(), O_CREAT|O_RDWR, 0600))){
S3FS_PRN_ERR("failed to open cache stat file path(%s) - errno(%d)", path.c_str(), errno);
return false;
}
}
scope_guard guard([&]() { close(tmpfd); });
// lock
if(-1 == flock(tmpfd, LOCK_EX)){
S3FS_PRN_ERR("failed to lock cache stat file(%s) - errno(%d)", path.c_str(), errno);
return false;
}
// seek top
if(0 != lseek(tmpfd, 0, SEEK_SET)){
S3FS_PRN_ERR("failed to lseek cache stat file(%s) - errno(%d)", path.c_str(), errno);
flock(tmpfd, LOCK_UN);
return false;
}
S3FS_PRN_DBG("file locked(%s - %s)", path.c_str(), sfile_path.c_str());
guard.dismiss();
fd = tmpfd;
return true;
}
bool CacheFileStat::Open()
{
return RawOpen(false);
}
bool CacheFileStat::ReadOnlyOpen()
{
return RawOpen(true);
}
bool CacheFileStat::Release()
{
if(-1 == fd){
// already release
return true;
}
// unlock
if(-1 == flock(fd, LOCK_UN)){
S3FS_PRN_ERR("failed to unlock cache stat file(%s) - errno(%d)", path.c_str(), errno);
return false;
}
S3FS_PRN_DBG("file unlocked(%s)", path.c_str());
if(-1 == close(fd)){
S3FS_PRN_ERR("failed to close cache stat file(%s) - errno(%d)", path.c_str(), errno);
return false;
}
fd = -1;
return true;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

71
src/fdcache_stat.h Normal file
View File

@ -0,0 +1,71 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_FDCACHE_STAT_H_
#define S3FS_FDCACHE_STAT_H_
#include <string>
//------------------------------------------------
// CacheFileStat
//------------------------------------------------
class CacheFileStat
{
private:
std::string path;
int fd;
private:
static int MakeCacheFileStatPath(const char* path, std::string& sfile_path, bool is_create_dir = true);
bool RawOpen(bool readonly);
public:
static std::string GetCacheFileStatTopDir();
static int DeleteCacheFileStat(const char* path);
static bool CheckCacheFileStatTopDir();
static bool DeleteCacheFileStatDirectory();
static bool RenameCacheFileStat(const char* oldpath, const char* newpath);
explicit CacheFileStat(const char* tpath = nullptr);
~CacheFileStat();
CacheFileStat(const CacheFileStat&) = delete;
CacheFileStat(CacheFileStat&&) = delete;
CacheFileStat& operator=(const CacheFileStat&) = delete;
CacheFileStat& operator=(CacheFileStat&&) = delete;
bool Open();
bool ReadOnlyOpen();
bool Release();
bool SetPath(const char* tpath, bool is_open = true);
int GetFd() const { return fd; }
bool OverWriteFile(const std::string& strall) const;
};
#endif // S3FS_FDCACHE_STAT_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

249
src/fdcache_untreated.cpp Normal file
View File

@ -0,0 +1,249 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Takeshi Nakatani <ggtakec.com>
*
* 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.
*/
#include <cstdlib>
#include <mutex>
#include "s3fs_logger.h"
#include "fdcache_untreated.h"
//------------------------------------------------
// UntreatedParts methods
//------------------------------------------------
bool UntreatedParts::empty() const
{
const std::lock_guard<std::mutex> lock(untreated_list_lock);
return untreated_list.empty();
}
bool UntreatedParts::AddPart(off_t start, off_t size)
{
if(start < 0 || size <= 0){
S3FS_PRN_ERR("Parameter are wrong(start=%lld, size=%lld).", static_cast<long long int>(start), static_cast<long long int>(size));
return false;
}
const std::lock_guard<std::mutex> lock(untreated_list_lock);
++last_tag;
// Check the overlap with the existing part and add the part.
for(auto iter = untreated_list.begin(); iter != untreated_list.end(); ++iter){
if(iter->stretch(start, size, last_tag)){
// the part was stretched, thus check if it overlaps with next parts
auto niter = iter;
for(++niter; niter != untreated_list.cend(); ){
if(!iter->stretch(niter->start, niter->size, last_tag)){
// This next part does not overlap with the current part
break;
}
// Since the parts overlap and the current part is stretched, delete this next part.
niter = untreated_list.erase(niter);
}
// success to stretch and compress existed parts
return true;
}else if((start + size) < iter->start){
// The part to add should be inserted before the current part.
untreated_list.insert(iter, untreatedpart(start, size, last_tag));
// success to stretch and compress existed parts
return true;
}
}
// There are no overlapping parts in the untreated_list, then add the part at end of list
untreated_list.emplace_back(start, size, last_tag);
return true;
}
bool UntreatedParts::RowGetPart(off_t& start, off_t& size, off_t max_size, off_t min_size, bool lastpart) const
{
if(max_size <= 0 || min_size < 0 || max_size < min_size){
S3FS_PRN_ERR("Parameter are wrong(max_size=%lld, min_size=%lld).", static_cast<long long int>(max_size), static_cast<long long int>(min_size));
return false;
}
const std::lock_guard<std::mutex> lock(untreated_list_lock);
// Check the overlap with the existing part and add the part.
for(auto iter = untreated_list.cbegin(); iter != untreated_list.cend(); ++iter){
if(!lastpart || iter->untreated_tag == last_tag){
if(min_size <= iter->size){
if(iter->size <= max_size){
// whole part( min <= part size <= max )
start = iter->start;
size = iter->size;
}else{
// Partially take out part( max < part size )
start = iter->start;
size = max_size;
}
return true;
}else{
if(lastpart){
return false;
}
}
}
}
return false;
}
// [NOTE]
// If size is specified as 0, all areas(parts) after start will be deleted.
//
bool UntreatedParts::ClearParts(off_t start, off_t size)
{
if(start < 0 || size < 0){
S3FS_PRN_ERR("Parameter are wrong(start=%lld, size=%lld).", static_cast<long long int>(start), static_cast<long long int>(size));
return false;
}
const std::lock_guard<std::mutex> lock(untreated_list_lock);
if(untreated_list.empty()){
return true;
}
// Check the overlap with the existing part.
for(auto iter = untreated_list.begin(); iter != untreated_list.end(); ){
if(0 != size && (start + size) <= iter->start){
// clear area is in front of iter area, no more to do.
break;
}else if(start <= iter->start){
if(0 != size && (start + size) <= (iter->start + iter->size)){
// clear area overlaps with iter area(on the start side)
iter->size = (iter->start + iter->size) - (start + size);
iter->start = start + size;
if(0 == iter->size){
iter = untreated_list.erase(iter);
}
}else{
// clear area overlaps with all of iter area
iter = untreated_list.erase(iter);
}
}else if(start < (iter->start + iter->size)){
// clear area overlaps with iter area(on the end side)
if(0 == size || (iter->start + iter->size) <= (start + size)){
// start to iter->end is clear
iter->size = start - iter->start;
}else{
// parse current part
iter->size = start - iter->start;
// add new part
off_t next_start = start + size;
off_t next_size = (iter->start + iter->size) - (start + size);
long next_tag = iter->untreated_tag;
++iter;
iter = untreated_list.insert(iter, untreatedpart(next_start, next_size, next_tag));
++iter;
}
}else{
// clear area is in behind of iter area
++iter;
}
}
return true;
}
//
// Update the last updated Untreated part
//
bool UntreatedParts::GetLastUpdatePart(off_t& start, off_t& size) const
{
const std::lock_guard<std::mutex> lock(untreated_list_lock);
for(auto iter = untreated_list.cbegin(); iter != untreated_list.cend(); ++iter){
if(iter->untreated_tag == last_tag){
start = iter->start;
size = iter->size;
return true;
}
}
return false;
}
//
// Replaces the last updated Untreated part.
//
// [NOTE]
// If size <= 0, delete that part
//
bool UntreatedParts::ReplaceLastUpdatePart(off_t start, off_t size)
{
const std::lock_guard<std::mutex> lock(untreated_list_lock);
for(auto iter = untreated_list.begin(); iter != untreated_list.end(); ++iter){
if(iter->untreated_tag == last_tag){
if(0 < size){
iter->start = start;
iter->size = size;
}else{
untreated_list.erase(iter);
}
return true;
}
}
return false;
}
//
// Remove the last updated Untreated part.
//
bool UntreatedParts::RemoveLastUpdatePart()
{
const std::lock_guard<std::mutex> lock(untreated_list_lock);
for(auto iter = untreated_list.begin(); iter != untreated_list.end(); ++iter){
if(iter->untreated_tag == last_tag){
untreated_list.erase(iter);
return true;
}
}
return false;
}
//
// Duplicate the internally untreated_list.
//
bool UntreatedParts::Duplicate(untreated_list_t& list)
{
const std::lock_guard<std::mutex> lock(untreated_list_lock);
list = untreated_list;
return true;
}
void UntreatedParts::Dump()
{
const std::lock_guard<std::mutex> lock(untreated_list_lock);
S3FS_PRN_DBG("untreated list = [");
for(auto iter = untreated_list.cbegin(); iter != untreated_list.cend(); ++iter){
S3FS_PRN_DBG(" {%014lld - %014lld : tag=%ld}", static_cast<long long int>(iter->start), static_cast<long long int>(iter->size), iter->untreated_tag);
}
S3FS_PRN_DBG("]");
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

77
src/fdcache_untreated.h Normal file
View File

@ -0,0 +1,77 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_FDCACHE_UNTREATED_H_
#define S3FS_FDCACHE_UNTREATED_H_
#include <mutex>
#include "common.h"
#include "types.h"
//------------------------------------------------
// Class UntreatedParts
//------------------------------------------------
class UntreatedParts
{
private:
mutable std::mutex untreated_list_lock; // protects untreated_list
untreated_list_t untreated_list GUARDED_BY(untreated_list_lock);
long last_tag GUARDED_BY(untreated_list_lock) = 0; // [NOTE] Use this to identify the latest updated part.
private:
bool RowGetPart(off_t& start, off_t& size, off_t max_size, off_t min_size, bool lastpart) const;
public:
UntreatedParts() = default;
~UntreatedParts() = default;
UntreatedParts(const UntreatedParts&) = delete;
UntreatedParts(UntreatedParts&&) = delete;
UntreatedParts& operator=(const UntreatedParts&) = delete;
UntreatedParts& operator=(UntreatedParts&&) = delete;
bool empty() const;
bool AddPart(off_t start, off_t size);
bool GetLastUpdatedPart(off_t& start, off_t& size, off_t max_size, off_t min_size = MIN_MULTIPART_SIZE) const { return RowGetPart(start, size, max_size, min_size, true); }
bool ClearParts(off_t start, off_t size);
bool ClearAll() { return ClearParts(0, 0); }
bool GetLastUpdatePart(off_t& start, off_t& size) const;
bool ReplaceLastUpdatePart(off_t start, off_t size);
bool RemoveLastUpdatePart();
bool Duplicate(untreated_list_t& list);
void Dump();
};
#endif // S3FS_FDCACHE_UNTREATED_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

303
src/filetimes.cpp Normal file
View File

@ -0,0 +1,303 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Takeshi Nakatani <ggtakec.com>
*
* 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.
*/
#include "filetimes.h"
#include "s3fs_logger.h"
#include "string_util.h"
//-------------------------------------------------------------------
// Utility functions
//-------------------------------------------------------------------
//
// result: -1 ts1 < ts2
// 0 ts1 == ts2
// 1 ts1 > ts2
//
bool valid_timespec(const struct timespec& ts)
{
if(0 > ts.tv_sec || UTIME_OMIT == ts.tv_nsec || UTIME_NOW == ts.tv_nsec){
return false;
}
return true;
}
//
// result: -1 ts1 < ts2
// 0 ts1 == ts2
// 1 ts1 > ts2
//
constexpr int compare_timespec(const struct timespec& ts1, const struct timespec& ts2)
{
if(ts1.tv_sec < ts2.tv_sec){
return -1;
}else if(ts1.tv_sec > ts2.tv_sec){
return 1;
}else{
if(ts1.tv_nsec < ts2.tv_nsec){
return -1;
}else if(ts1.tv_nsec > ts2.tv_nsec){
return 1;
}
}
return 0;
}
//
// result: -1 st < ts
// 0 st == ts
// 1 st > ts
//
int compare_timespec(const struct stat& st, stat_time_type type, const struct timespec& ts)
{
struct timespec st_ts;
set_stat_to_timespec(st, type, st_ts);
return compare_timespec(st_ts, ts);
}
void set_timespec_to_stat(struct stat& st, stat_time_type type, const struct timespec& ts)
{
if(stat_time_type::ATIME == type){
#ifdef __APPLE__
st.st_atime = ts.tv_sec;
st.st_atimespec.tv_nsec = ts.tv_nsec;
#else
st.st_atim.tv_sec = ts.tv_sec;
st.st_atim.tv_nsec = ts.tv_nsec;
#endif
}else if(stat_time_type::MTIME == type){
#ifdef __APPLE__
st.st_mtime = ts.tv_sec;
st.st_mtimespec.tv_nsec = ts.tv_nsec;
#else
st.st_mtim.tv_sec = ts.tv_sec;
st.st_mtim.tv_nsec = ts.tv_nsec;
#endif
}else if(stat_time_type::CTIME == type){
#ifdef __APPLE__
st.st_ctime = ts.tv_sec;
st.st_ctimespec.tv_nsec = ts.tv_nsec;
#else
st.st_ctim.tv_sec = ts.tv_sec;
st.st_ctim.tv_nsec = ts.tv_nsec;
#endif
}else{
S3FS_PRN_ERR("unknown type(%d), so skip to set value.", static_cast<int>(type));
}
}
struct timespec* set_stat_to_timespec(const struct stat& st, stat_time_type type, struct timespec& ts)
{
if(stat_time_type::ATIME == type){
#ifdef __APPLE__
ts.tv_sec = st.st_atime;
ts.tv_nsec = st.st_atimespec.tv_nsec;
#else
ts = st.st_atim;
#endif
}else if(stat_time_type::MTIME == type){
#ifdef __APPLE__
ts.tv_sec = st.st_mtime;
ts.tv_nsec = st.st_mtimespec.tv_nsec;
#else
ts = st.st_mtim;
#endif
}else if(stat_time_type::CTIME == type){
#ifdef __APPLE__
ts.tv_sec = st.st_ctime;
ts.tv_nsec = st.st_ctimespec.tv_nsec;
#else
ts = st.st_ctim;
#endif
}else{
S3FS_PRN_ERR("unknown type(%d), so use 0 as timespec.", static_cast<int>(type));
ts.tv_sec = 0;
ts.tv_nsec = 0;
}
return &ts;
}
std::string str_stat_time(const struct stat& st, stat_time_type type)
{
struct timespec ts;
return str(*set_stat_to_timespec(st, type, ts));
}
struct timespec* s3fs_realtime(struct timespec& ts)
{
if(-1 == clock_gettime(static_cast<clockid_t>(CLOCK_REALTIME), &ts)){
S3FS_PRN_WARN("failed to clock_gettime by errno(%d)", errno);
ts.tv_sec = time(nullptr);
ts.tv_nsec = 0;
}
return &ts;
}
std::string s3fs_str_realtime()
{
struct timespec ts;
return str(*s3fs_realtime(ts));
}
//-------------------------------------------------------------------
// FileTimes Class
//-------------------------------------------------------------------
void FileTimes::Clear()
{
ClearCTime();
ClearATime();
ClearMTime();
}
void FileTimes::Clear(stat_time_type type)
{
if(stat_time_type::CTIME == type){
ft_ctime = {0, UTIME_OMIT};
}else if(stat_time_type::ATIME == type){
ft_atime = {0, UTIME_OMIT};
}else{ // stat_time_type::MTIME
ft_mtime = {0, UTIME_OMIT};
}
}
const struct timespec& FileTimes::GetTime(stat_time_type type) const
{
if(stat_time_type::CTIME == type){
return ft_ctime;
}else if(stat_time_type::ATIME == type){
return ft_atime;
}else{ // stat_time_type::MTIME
return ft_mtime;
}
}
void FileTimes::GetTime(stat_time_type type, struct timespec& time) const
{
if(stat_time_type::CTIME == type){
time = ft_ctime;
}else if(stat_time_type::ATIME == type){
time = ft_atime;
}else{ // stat_time_type::MTIME
time = ft_mtime;
}
}
void FileTimes::ReflectFileTimes(struct stat& st) const
{
if(!IsOmitCTime()){
set_timespec_to_stat(st, stat_time_type::CTIME, ft_ctime);
}
if(!IsOmitATime()){
set_timespec_to_stat(st, stat_time_type::ATIME, ft_atime);
}
if(!IsOmitMTime()){
set_timespec_to_stat(st, stat_time_type::MTIME, ft_mtime);
}
}
void FileTimes::SetTime(stat_time_type type, struct timespec time)
{
if(UTIME_NOW == time.tv_nsec){
s3fs_realtime(time);
}
if(stat_time_type::CTIME == type){
ft_ctime = time;
}else if(stat_time_type::ATIME == type){
ft_atime = time;
}else{ // stat_time_type::MTIME
ft_mtime = time;
}
}
void FileTimes::SetAllNow()
{
struct timespec time;
s3fs_realtime(time);
SetAll(time, time, time);
}
void FileTimes::SetAll(const struct stat& stbuf, bool no_omit)
{
struct timespec ts_ctime;
struct timespec ts_atime;
struct timespec ts_mtime;
set_stat_to_timespec(stbuf, stat_time_type::CTIME, ts_ctime);
set_stat_to_timespec(stbuf, stat_time_type::ATIME, ts_atime);
set_stat_to_timespec(stbuf, stat_time_type::MTIME, ts_mtime);
SetAll(ts_ctime, ts_atime, ts_mtime, no_omit);
}
void FileTimes::SetAll(struct timespec ts_ctime, struct timespec ts_atime, struct timespec ts_mtime, bool no_omit)
{
struct timespec ts_now_time;
s3fs_realtime(ts_now_time);
if(UTIME_NOW == ts_ctime.tv_nsec){
SetCTime(ts_now_time);
}else if(!no_omit || UTIME_OMIT != ts_ctime.tv_nsec){
SetCTime(ts_ctime);
}
if(UTIME_NOW == ts_atime.tv_nsec){
SetATime(ts_now_time);
}else if(!no_omit || UTIME_OMIT != ts_atime.tv_nsec){
SetATime(ts_atime);
}
if(UTIME_NOW == ts_mtime.tv_nsec){
SetMTime(ts_now_time);
}else if(!no_omit || UTIME_OMIT != ts_mtime.tv_nsec){
SetMTime(ts_mtime);
}
}
void FileTimes::SetAll(const FileTimes& other, bool no_omit)
{
if(!no_omit || !other.IsOmitCTime()){
SetCTime(other.ctime());
}
if(!no_omit || !other.IsOmitATime()){
SetATime(other.atime());
}
if(!no_omit || !other.IsOmitMTime()){
SetMTime(other.mtime());
}
}
bool FileTimes::IsOmit(stat_time_type type) const
{
if(stat_time_type::CTIME == type){
return (UTIME_OMIT == ft_ctime.tv_nsec);
}else if(stat_time_type::ATIME == type){
return (UTIME_OMIT == ft_atime.tv_nsec);
}else{ // stat_time_type::MTIME
return (UTIME_OMIT == ft_mtime.tv_nsec);
}
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

120
src/filetimes.h Normal file
View File

@ -0,0 +1,120 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_FILETIMES_H_
#define S3FS_FILETIMES_H_
#include <cstdint>
#include <string>
#include <sys/stat.h>
//-------------------------------------------------------------------
// Utility for stat time type
//-------------------------------------------------------------------
enum class stat_time_type : uint8_t {
ATIME,
MTIME,
CTIME
};
//-------------------------------------------------------------------
// Utility Functions for timespecs
//-------------------------------------------------------------------
bool valid_timespec(const struct timespec& ts);
constexpr int compare_timespec(const struct timespec& ts1, const struct timespec& ts2);
int compare_timespec(const struct stat& st, stat_time_type type, const struct timespec& ts);
void set_timespec_to_stat(struct stat& st, stat_time_type type, const struct timespec& ts);
struct timespec* set_stat_to_timespec(const struct stat& st, stat_time_type type, struct timespec& ts);
std::string str_stat_time(const struct stat& st, stat_time_type type);
struct timespec* s3fs_realtime(struct timespec& ts);
std::string s3fs_str_realtime();
//-------------------------------------------------------------------
// FileTimes Class
//-------------------------------------------------------------------
// [NOTE]
// In this class, UTIME_OMIT is set when initializing or clearing
// internal data.
// Also, if UTIME_NOW is specified, the value will be corrected to
// the current time and maintained.
//
class FileTimes
{
private:
struct timespec ft_ctime; // Change time
struct timespec ft_atime; // Access time
struct timespec ft_mtime; // Modification time
private:
void Clear(stat_time_type type);
const struct timespec& GetTime(stat_time_type type) const;
void GetTime(stat_time_type type, struct timespec& time) const;
void SetTime(stat_time_type type, struct timespec time);
bool IsOmit(stat_time_type type) const;
public:
explicit FileTimes() : ft_ctime{0, UTIME_OMIT}, ft_atime{0, UTIME_OMIT}, ft_mtime{0, UTIME_OMIT} {}
// Clear
void Clear();
void ClearCTime() { Clear(stat_time_type::CTIME); }
void ClearATime() { Clear(stat_time_type::ATIME); }
void ClearMTime() { Clear(stat_time_type::MTIME); }
// Get value
const struct timespec& ctime() const { return GetTime(stat_time_type::CTIME); }
const struct timespec& atime() const { return GetTime(stat_time_type::ATIME); }
const struct timespec& mtime() const { return GetTime(stat_time_type::MTIME); }
void GetCTime(struct timespec& time) const { GetTime(stat_time_type::CTIME, time); }
void GetATime(struct timespec& time) const { GetTime(stat_time_type::ATIME, time); }
void GetMTime(struct timespec& time) const { GetTime(stat_time_type::MTIME, time); }
void ReflectFileTimes(struct stat& st) const;
// Set value
void SetCTime(struct timespec time) { SetTime(stat_time_type::CTIME, time); }
void SetATime(struct timespec time) { SetTime(stat_time_type::ATIME, time); }
void SetMTime(struct timespec time) { SetTime(stat_time_type::MTIME, time); }
void SetAllNow();
void SetAll(const struct stat& stbuf, bool no_omit = true);
void SetAll(struct timespec ts_ctime, struct timespec ts_atime, struct timespec ts_mtime, bool no_omit = true);
void SetAll(const FileTimes& other, bool no_omit = true);
// Check
bool IsOmitCTime() const { return IsOmit(stat_time_type::CTIME); }
bool IsOmitATime() const { return IsOmit(stat_time_type::ATIME); }
bool IsOmitMTime() const { return IsOmit(stat_time_type::MTIME); }
};
#endif // S3FS_FILETIMES_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

View File

@ -1,7 +1,7 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright 2007-2008 Randy Rizun <rrizun@gmail.com>
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -18,19 +18,18 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <gcrypt.h>
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#ifdef USE_GNUTLS_NETTLE
#ifdef USE_GNUTLS_NETTLE
#include <nettle/md5.h>
#include <nettle/sha1.h>
#include <nettle/hmac.h>
@ -39,415 +38,353 @@
#include <map>
#include "common.h"
#include "s3fs.h"
#include "s3fs_auth.h"
using namespace std;
#include "s3fs_logger.h"
//-------------------------------------------------------------------
// Utility Function for version
//-------------------------------------------------------------------
#ifdef USE_GNUTLS_NETTLE
#ifdef USE_GNUTLS_NETTLE
const char* s3fs_crypt_lib_name(void)
{
static const char version[] = "GnuTLS(nettle)";
static constexpr char version[] = "GnuTLS(nettle)";
return version;
return version;
}
#else // USE_GNUTLS_NETTLE
#else // USE_GNUTLS_NETTLE
const char* s3fs_crypt_lib_name(void)
const char* s3fs_crypt_lib_name()
{
static const char version[] = "GnuTLS(gcrypt)";
static constexpr char version[] = "GnuTLS(gcrypt)";
return version;
return version;
}
#endif // USE_GNUTLS_NETTLE
#endif // USE_GNUTLS_NETTLE
//-------------------------------------------------------------------
// Utility Function for global init
//-------------------------------------------------------------------
bool s3fs_init_global_ssl(void)
bool s3fs_init_global_ssl()
{
if(GNUTLS_E_SUCCESS != gnutls_global_init()){
return false;
}
return true;
if(GNUTLS_E_SUCCESS != gnutls_global_init()){
return false;
}
#ifndef USE_GNUTLS_NETTLE
if(nullptr == gcry_check_version(nullptr)){
return false;
}
#endif // USE_GNUTLS_NETTLE
return true;
}
bool s3fs_destroy_global_ssl(void)
bool s3fs_destroy_global_ssl()
{
gnutls_global_deinit();
return true;
gnutls_global_deinit();
return true;
}
//-------------------------------------------------------------------
// Utility Function for crypt lock
//-------------------------------------------------------------------
bool s3fs_init_crypt_mutex(void)
bool s3fs_init_crypt_mutex()
{
return true;
return true;
}
bool s3fs_destroy_crypt_mutex(void)
bool s3fs_destroy_crypt_mutex()
{
return true;
return true;
}
//-------------------------------------------------------------------
// Utility Function for HMAC
//-------------------------------------------------------------------
#ifdef USE_GNUTLS_NETTLE
#ifdef USE_GNUTLS_NETTLE
bool s3fs_HMAC(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned char** digest, unsigned int* digestlen)
std::unique_ptr<unsigned char[]> s3fs_HMAC(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned int* digestlen)
{
if(!key || 0 >= keylen || !data || 0 >= datalen || !digest || !digestlen){
return false;
}
if(!key || !data || !digestlen){
return nullptr;
}
if(NULL == (*digest = (unsigned char*)malloc(SHA1_DIGEST_SIZE))){
return false;
}
auto digest = std::make_unique<unsigned char[]>(SHA1_DIGEST_SIZE);
struct hmac_sha1_ctx ctx_hmac;
hmac_sha1_set_key(&ctx_hmac, keylen, reinterpret_cast<const uint8_t*>(key));
hmac_sha1_update(&ctx_hmac, datalen, reinterpret_cast<const uint8_t*>(data));
hmac_sha1_digest(&ctx_hmac, SHA1_DIGEST_SIZE, reinterpret_cast<uint8_t*>(*digest));
*digestlen = SHA1_DIGEST_SIZE;
struct hmac_sha1_ctx ctx_hmac;
hmac_sha1_set_key(&ctx_hmac, keylen, reinterpret_cast<const uint8_t*>(key));
hmac_sha1_update(&ctx_hmac, datalen, reinterpret_cast<const uint8_t*>(data));
hmac_sha1_digest(&ctx_hmac, SHA1_DIGEST_SIZE, reinterpret_cast<uint8_t*>(digest.get()));
*digestlen = SHA1_DIGEST_SIZE;
return true;
return digest;
}
bool s3fs_HMAC256(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned char** digest, unsigned int* digestlen)
std::unique_ptr<unsigned char[]> s3fs_HMAC256(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned int* digestlen)
{
if(!key || 0 >= keylen || !data || 0 >= datalen || !digest || !digestlen){
return false;
}
if(!key || !data || !digestlen){
return nullptr;
}
if(NULL == (*digest = (unsigned char*)malloc(SHA256_DIGEST_SIZE))){
return false;
}
auto digest = std::make_unique<unsigned char[]>(SHA256_DIGEST_SIZE);
struct hmac_sha256_ctx ctx_hmac;
hmac_sha256_set_key(&ctx_hmac, keylen, reinterpret_cast<const uint8_t*>(key));
hmac_sha256_update(&ctx_hmac, datalen, reinterpret_cast<const uint8_t*>(data));
hmac_sha256_digest(&ctx_hmac, SHA256_DIGEST_SIZE, reinterpret_cast<uint8_t*>(*digest));
*digestlen = SHA256_DIGEST_SIZE;
struct hmac_sha256_ctx ctx_hmac;
hmac_sha256_set_key(&ctx_hmac, keylen, reinterpret_cast<const uint8_t*>(key));
hmac_sha256_update(&ctx_hmac, datalen, reinterpret_cast<const uint8_t*>(data));
hmac_sha256_digest(&ctx_hmac, SHA256_DIGEST_SIZE, reinterpret_cast<uint8_t*>(digest.get()));
*digestlen = SHA256_DIGEST_SIZE;
return true;
return digest;
}
#else // USE_GNUTLS_NETTLE
#else // USE_GNUTLS_NETTLE
bool s3fs_HMAC(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned char** digest, unsigned int* digestlen)
std::unique_ptr<unsigned char[]> s3fs_HMAC(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned int* digestlen)
{
if(!key || 0 >= keylen || !data || 0 >= datalen || !digest || !digestlen){
return false;
}
if(!key || !data || !digestlen){
return nullptr;
}
if(0 >= (*digestlen = gnutls_hmac_get_len(GNUTLS_MAC_SHA1))){
return false;
}
if(NULL == (*digest = (unsigned char*)malloc(*digestlen + 1))){
return false;
}
if(0 > gnutls_hmac_fast(GNUTLS_MAC_SHA1, key, keylen, data, datalen, *digest)){
free(*digest);
*digest = NULL;
return false;
}
return true;
if(0 == (*digestlen = gnutls_hmac_get_len(GNUTLS_MAC_SHA1))){
return nullptr;
}
auto digest = std::make_unique<unsigned char[]>(*digestlen + 1);
if(0 > gnutls_hmac_fast(GNUTLS_MAC_SHA1, key, keylen, data, datalen, digest.get())){
return nullptr;
}
return digest;
}
bool s3fs_HMAC256(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned char** digest, unsigned int* digestlen)
std::unique_ptr<unsigned char[]> s3fs_HMAC256(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned int* digestlen)
{
if(!key || 0 >= keylen || !data || 0 >= datalen || !digest || !digestlen){
return false;
}
if(!key || !data || !digestlen){
return nullptr;
}
if(0 >= (*digestlen = gnutls_hmac_get_len(GNUTLS_MAC_SHA256))){
return false;
}
if(NULL == (*digest = (unsigned char*)malloc(*digestlen + 1))){
return false;
}
if(0 > gnutls_hmac_fast(GNUTLS_MAC_SHA256, key, keylen, data, datalen, *digest)){
free(*digest);
*digest = NULL;
return false;
}
return true;
if(0 == (*digestlen = gnutls_hmac_get_len(GNUTLS_MAC_SHA256))){
return nullptr;
}
auto digest = std::make_unique<unsigned char[]>(*digestlen + 1);
if(0 > gnutls_hmac_fast(GNUTLS_MAC_SHA256, key, keylen, data, datalen, digest.get())){
return nullptr;
}
return digest;
}
#endif // USE_GNUTLS_NETTLE
#endif // USE_GNUTLS_NETTLE
//-------------------------------------------------------------------
// Utility Function for MD5
//-------------------------------------------------------------------
#define MD5_DIGEST_LENGTH 16
size_t get_md5_digest_length(void)
#ifdef USE_GNUTLS_NETTLE
bool s3fs_md5(const unsigned char* data, size_t datalen, md5_t* result)
{
return MD5_DIGEST_LENGTH;
struct md5_ctx ctx_md5;
md5_init(&ctx_md5);
md5_update(&ctx_md5, datalen, data);
md5_digest(&ctx_md5, result->size(), result->data());
return true;
}
#ifdef USE_GNUTLS_NETTLE
unsigned char* s3fs_md5hexsum(int fd, off_t start, ssize_t size)
bool s3fs_md5_fd(int fd, off_t start, off_t size, md5_t* result)
{
struct md5_ctx ctx_md5;
unsigned char buf[512];
ssize_t bytes;
unsigned char* result;
struct md5_ctx ctx_md5;
off_t bytes;
// seek to top of file.
if(-1 == lseek(fd, start, SEEK_SET)){
return NULL;
}
memset(buf, 0, 512);
md5_init(&ctx_md5);
for(ssize_t total = 0; total < size; total += bytes){
bytes = 512 < (size - total) ? 512 : (size - total);
bytes = read(fd, buf, bytes);
if(0 == bytes){
// end of file
break;
}else if(-1 == bytes){
// error
S3FS_PRN_ERR("file read error(%d)", errno);
return NULL;
if(-1 == size){
struct stat st;
if(-1 == fstat(fd, &st)){
return false;
}
size = st.st_size;
}
md5_update(&ctx_md5, bytes, buf);
memset(buf, 0, 512);
}
if(NULL == (result = (unsigned char*)malloc(get_md5_digest_length()))){
return NULL;
}
md5_digest(&ctx_md5, get_md5_digest_length(), result);
if(-1 == lseek(fd, start, SEEK_SET)){
free(result);
return NULL;
}
md5_init(&ctx_md5);
return result;
for(off_t total = 0; total < size; total += bytes){
std::array<char, 512> buf;
bytes = std::min(static_cast<off_t>(buf.size()), (size - total));
bytes = pread(fd, buf.data(), bytes, start + total);
if(0 == bytes){
// end of file
break;
}else if(-1 == bytes){
// error
S3FS_PRN_ERR("file read error(%d)", errno);
return false;
}
md5_update(&ctx_md5, bytes, reinterpret_cast<const uint8_t*>(buf.data()));
}
md5_digest(&ctx_md5, result->size(), result->data());
return true;
}
#else // USE_GNUTLS_NETTLE
#else // USE_GNUTLS_NETTLE
unsigned char* s3fs_md5hexsum(int fd, off_t start, ssize_t size)
bool s3fs_md5(const unsigned char* data, size_t datalen, md5_t* digest)
{
gcry_md_hd_t ctx_md5;
gcry_error_t err;
char buf[512];
ssize_t bytes;
unsigned char* result;
if(-1 == size){
struct stat st;
if(-1 == fstat(fd, &st)){
return NULL;
gcry_md_hd_t ctx_md5;
gcry_error_t err;
if(GPG_ERR_NO_ERROR != (err = gcry_md_open(&ctx_md5, GCRY_MD_MD5, 0))){
S3FS_PRN_ERR("MD5 context creation failure: %s/%s", gcry_strsource(err), gcry_strerror(err));
return false;
}
size = static_cast<ssize_t>(st.st_size);
}
gcry_md_write(ctx_md5, digest->data(), digest->size());
gcry_md_close(ctx_md5);
// seek to top of file.
if(-1 == lseek(fd, start, SEEK_SET)){
return NULL;
}
memset(buf, 0, 512);
if(GPG_ERR_NO_ERROR != (err = gcry_md_open(&ctx_md5, GCRY_MD_MD5, 0))){
S3FS_PRN_ERR("MD5 context creation failure: %s/%s", gcry_strsource(err), gcry_strerror(err));
return NULL;
}
for(ssize_t total = 0; total < size; total += bytes){
bytes = 512 < (size - total) ? 512 : (size - total);
bytes = read(fd, buf, bytes);
if(0 == bytes){
// end of file
break;
}else if(-1 == bytes){
// error
S3FS_PRN_ERR("file read error(%d)", errno);
return NULL;
}
gcry_md_write(ctx_md5, buf, bytes);
memset(buf, 0, 512);
}
if(NULL == (result = (unsigned char*)malloc(get_md5_digest_length()))){
return NULL;
}
memcpy(result, gcry_md_read(ctx_md5, 0), get_md5_digest_length());
gcry_md_close(ctx_md5);
if(-1 == lseek(fd, start, SEEK_SET)){
free(result);
return NULL;
}
return result;
return true;
}
#endif // USE_GNUTLS_NETTLE
bool s3fs_md5_fd(int fd, off_t start, off_t size, md5_t* result)
{
gcry_md_hd_t ctx_md5;
gcry_error_t err;
off_t bytes;
if(-1 == size){
struct stat st;
if(-1 == fstat(fd, &st)){
return false;
}
size = st.st_size;
}
if(GPG_ERR_NO_ERROR != (err = gcry_md_open(&ctx_md5, GCRY_MD_MD5, 0))){
S3FS_PRN_ERR("MD5 context creation failure: %s/%s", gcry_strsource(err), gcry_strerror(err));
return false;
}
for(off_t total = 0; total < size; total += bytes){
std::array<char, 512> buf;
bytes = std::min(static_cast<off_t>(buf.size()), (size - total));
bytes = pread(fd, buf.data(), bytes, start + total);
if(0 == bytes){
// end of file
break;
}else if(-1 == bytes){
// error
S3FS_PRN_ERR("file read error(%d)", errno);
gcry_md_close(ctx_md5);
return false;
}
gcry_md_write(ctx_md5, buf.data(), bytes);
}
memcpy(result->data(), gcry_md_read(ctx_md5, 0), result->size());
gcry_md_close(ctx_md5);
return true;
}
#endif // USE_GNUTLS_NETTLE
//-------------------------------------------------------------------
// Utility Function for SHA256
//-------------------------------------------------------------------
#define SHA256_DIGEST_LENGTH 32
size_t get_sha256_digest_length(void)
#ifdef USE_GNUTLS_NETTLE
bool s3fs_sha256(const unsigned char* data, size_t datalen, sha256_t* digest)
{
return SHA256_DIGEST_LENGTH;
struct sha256_ctx ctx_sha256;
sha256_init(&ctx_sha256);
sha256_update(&ctx_sha256, datalen, data);
sha256_digest(&ctx_sha256, digest->size(), digest->data());
return true;
}
#ifdef USE_GNUTLS_NETTLE
bool s3fs_sha256(const unsigned char* data, unsigned int datalen, unsigned char** digest, unsigned int* digestlen)
bool s3fs_sha256_fd(int fd, off_t start, off_t size, sha256_t* result)
{
(*digestlen) = static_cast<unsigned int>(get_sha256_digest_length());
if(NULL == ((*digest) = reinterpret_cast<unsigned char*>(malloc(*digestlen)))){
return false;
}
struct sha256_ctx ctx_sha256;
off_t bytes;
struct sha256_ctx ctx_sha256;
sha256_init(&ctx_sha256);
sha256_update(&ctx_sha256, datalen, data);
sha256_digest(&ctx_sha256, *digestlen, *digest);
sha256_init(&ctx_sha256);
return true;
}
unsigned char* s3fs_sha256hexsum(int fd, off_t start, ssize_t size)
{
struct sha256_ctx ctx_sha256;
unsigned char buf[512];
ssize_t bytes;
unsigned char* result;
// seek to top of file.
if(-1 == lseek(fd, start, SEEK_SET)){
return NULL;
}
memset(buf, 0, 512);
sha256_init(&ctx_sha256);
for(ssize_t total = 0; total < size; total += bytes){
bytes = 512 < (size - total) ? 512 : (size - total);
bytes = read(fd, buf, bytes);
if(0 == bytes){
// end of file
break;
}else if(-1 == bytes){
// error
S3FS_PRN_ERR("file read error(%d)", errno);
return NULL;
for(off_t total = 0; total < size; total += bytes){
std::array<char, 512> buf;
bytes = std::min(static_cast<off_t>(buf.size()), (size - total));
bytes = pread(fd, buf.data(), bytes, start + total);
if(0 == bytes){
// end of file
break;
}else if(-1 == bytes){
// error
S3FS_PRN_ERR("file read error(%d)", errno);
return false;
}
sha256_update(&ctx_sha256, bytes, reinterpret_cast<const uint8_t*>(buf.data()));
}
sha256_update(&ctx_sha256, bytes, buf);
memset(buf, 0, 512);
}
if(NULL == (result = (unsigned char*)malloc(get_sha256_digest_length()))){
return NULL;
}
sha256_digest(&ctx_sha256, get_sha256_digest_length(), result);
sha256_digest(&ctx_sha256, result->size(), result->data());
if(-1 == lseek(fd, start, SEEK_SET)){
free(result);
return NULL;
}
return result;
return true;
}
#else // USE_GNUTLS_NETTLE
#else // USE_GNUTLS_NETTLE
bool s3fs_sha256(const unsigned char* data, unsigned int datalen, unsigned char** digest, unsigned int* digestlen)
bool s3fs_sha256(const unsigned char* data, size_t datalen, sha256_t* digest)
{
(*digestlen) = static_cast<unsigned int>(get_sha256_digest_length());
if(NULL == ((*digest) = reinterpret_cast<unsigned char*>(malloc(*digestlen)))){
return false;
}
gcry_md_hd_t ctx_sha256;
gcry_error_t err;
if(GPG_ERR_NO_ERROR != (err = gcry_md_open(&ctx_sha256, GCRY_MD_SHA256, 0))){
S3FS_PRN_ERR("SHA256 context creation failure: %s/%s", gcry_strsource(err), gcry_strerror(err));
return false;
}
gcry_md_write(ctx_sha256, data, datalen);
memcpy(digest->data(), gcry_md_read(ctx_sha256, 0), digest->size());
gcry_md_close(ctx_sha256);
gcry_md_hd_t ctx_sha256;
gcry_error_t err;
if(GPG_ERR_NO_ERROR != (err = gcry_md_open(&ctx_sha256, GCRY_MD_SHA256, 0))){
S3FS_PRN_ERR("SHA256 context creation failure: %s/%s", gcry_strsource(err), gcry_strerror(err));
free(*digest);
return false;
}
gcry_md_write(ctx_sha256, data, datalen);
memcpy(*digest, gcry_md_read(ctx_sha256, 0), *digestlen);
gcry_md_close(ctx_sha256);
return true;
return true;
}
unsigned char* s3fs_sha256hexsum(int fd, off_t start, ssize_t size)
bool s3fs_sha256_fd(int fd, off_t start, off_t size, sha256_t* result)
{
gcry_md_hd_t ctx_sha256;
gcry_error_t err;
char buf[512];
ssize_t bytes;
unsigned char* result;
gcry_md_hd_t ctx_sha256;
gcry_error_t err;
off_t bytes;
if(-1 == size){
struct stat st;
if(-1 == fstat(fd, &st)){
return NULL;
if(-1 == size){
struct stat st;
if(-1 == fstat(fd, &st)){
return false;
}
size = st.st_size;
}
size = static_cast<ssize_t>(st.st_size);
}
// seek to top of file.
if(-1 == lseek(fd, start, SEEK_SET)){
return NULL;
}
memset(buf, 0, 512);
if(GPG_ERR_NO_ERROR != (err = gcry_md_open(&ctx_sha256, GCRY_MD_SHA256, 0))){
S3FS_PRN_ERR("SHA256 context creation failure: %s/%s", gcry_strsource(err), gcry_strerror(err));
return NULL;
}
for(ssize_t total = 0; total < size; total += bytes){
bytes = 512 < (size - total) ? 512 : (size - total);
bytes = read(fd, buf, bytes);
if(0 == bytes){
// end of file
break;
}else if(-1 == bytes){
// error
S3FS_PRN_ERR("file read error(%d)", errno);
return NULL;
if(GPG_ERR_NO_ERROR != (err = gcry_md_open(&ctx_sha256, GCRY_MD_SHA256, 0))){
S3FS_PRN_ERR("SHA256 context creation failure: %s/%s", gcry_strsource(err), gcry_strerror(err));
return false;
}
gcry_md_write(ctx_sha256, buf, bytes);
memset(buf, 0, 512);
}
if(NULL == (result = (unsigned char*)malloc(get_sha256_digest_length()))){
return NULL;
}
memcpy(result, gcry_md_read(ctx_sha256, 0), get_sha256_digest_length());
gcry_md_close(ctx_sha256);
if(-1 == lseek(fd, start, SEEK_SET)){
free(result);
return NULL;
}
for(off_t total = 0; total < size; total += bytes){
std::array<char, 512> buf;
bytes = std::min(static_cast<off_t>(buf.size()), (size - total));
bytes = pread(fd, buf.data(), bytes, start + total);
if(0 == bytes){
// end of file
break;
}else if(-1 == bytes){
// error
S3FS_PRN_ERR("file read error(%d)", errno);
gcry_md_close(ctx_sha256);
return false;
}
gcry_md_write(ctx_sha256, buf.data(), bytes);
}
memcpy(result->data(), gcry_md_read(ctx_sha256, 0), result->size());
gcry_md_close(ctx_sha256);
return result;
return true;
}
#endif // USE_GNUTLS_NETTLE
#endif // USE_GNUTLS_NETTLE
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

493
src/metaheader.cpp Normal file
View File

@ -0,0 +1,493 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Takeshi Nakatani <ggtakec.com>
*
* 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.
*/
#include <ctime>
#include <string>
#include <sys/stat.h>
#include <unistd.h>
#include "common.h"
#include "metaheader.h"
#include "string_util.h"
#include "s3fs_util.h"
#include "filetimes.h"
static constexpr struct timespec ERROR_TIMESPEC = {-1, 0};
static constexpr struct timespec OMIT_TIMESPEC = {0, UTIME_OMIT};
//-------------------------------------------------------------------
// Utility functions for convert
//-------------------------------------------------------------------
static struct timespec cvt_string_to_time(const char *str)
{
// [NOTE]
// In rclone, there are cases where ns is set to x-amz-meta-mtime
// with floating point number. s3fs uses x-amz-meta-mtime by
// truncating the floating point or less (in seconds or less) to
// correspond to this.
//
std::string strmtime;
long nsec = 0;
if(str && '\0' != *str){
strmtime = str;
std::string::size_type pos = strmtime.find('.', 0);
if(std::string::npos != pos){
nsec = cvt_strtoofft(strmtime.substr(pos + 1).c_str(), /*base=*/ 10);
strmtime.erase(pos);
}
}
struct timespec ts = {static_cast<time_t>(cvt_strtoofft(strmtime.c_str(), /*base=*/ 10)), nsec};
return ts;
}
static struct timespec get_time(const headers_t& meta, const char *header)
{
headers_t::const_iterator iter;
if(meta.cend() == (iter = meta.find(header))){
return ERROR_TIMESPEC;
}
return cvt_string_to_time((*iter).second.c_str());
}
struct timespec get_mtime(const headers_t& meta, bool overcheck)
{
struct timespec mtime = get_time(meta, "x-amz-meta-mtime");
if(0 <= mtime.tv_sec && UTIME_OMIT != mtime.tv_nsec){
return mtime;
}
mtime = get_time(meta, "x-amz-meta-goog-reserved-file-mtime");
if(0 <= mtime.tv_sec && UTIME_OMIT != mtime.tv_nsec){
return mtime;
}
if(overcheck){
mtime = {get_lastmodified(meta), 0};
return mtime;
}
return OMIT_TIMESPEC;
}
struct timespec get_ctime(const headers_t& meta, bool overcheck)
{
struct timespec ctime = get_time(meta, "x-amz-meta-ctime");
if(0 <= ctime.tv_sec && UTIME_OMIT != ctime.tv_nsec){
return ctime;
}
if(overcheck){
ctime = {get_lastmodified(meta), 0};
return ctime;
}
return OMIT_TIMESPEC;
}
struct timespec get_atime(const headers_t& meta, bool overcheck)
{
struct timespec atime = get_time(meta, "x-amz-meta-atime");
if(0 <= atime.tv_sec && UTIME_OMIT != atime.tv_nsec){
return atime;
}
if(overcheck){
atime = {get_lastmodified(meta), 0};
return atime;
}
return OMIT_TIMESPEC;
}
off_t get_size(const char *s)
{
return cvt_strtoofft(s, /*base=*/ 10);
}
off_t get_size(const headers_t& meta)
{
auto iter = meta.find("Content-Length");
if(meta.cend() == iter){
return 0;
}
return get_size((*iter).second.c_str());
}
mode_t get_mode(const char *s, int base)
{
return static_cast<mode_t>(cvt_strtoofft(s, base));
}
mode_t get_mode(const headers_t& meta, const std::string& strpath, bool checkdir, bool forcedir)
{
mode_t mode = 0;
bool isS3sync = false;
headers_t::const_iterator iter;
if(meta.cend() != (iter = meta.find("x-amz-meta-mode"))){
mode = get_mode((*iter).second.c_str());
}else if(meta.cend() != (iter = meta.find("x-amz-meta-permissions"))){ // for s3sync
mode = get_mode((*iter).second.c_str());
isS3sync = true;
}else if(meta.cend() != (iter = meta.find("x-amz-meta-goog-reserved-posix-mode"))){ // for GCS
mode = get_mode((*iter).second.c_str(), 8);
}else{
// If another tool creates an object without permissions, default to owner
// read-write and group readable.
mode = (!strpath.empty() && '/' == *strpath.rbegin()) ? 0750 : 0640;
}
// Checking the bitmask, if the last 3 bits are all zero then process as a regular
// file type (S_IFDIR or S_IFREG), otherwise return mode unmodified so that S_IFIFO,
// S_IFSOCK, S_IFCHR, S_IFLNK and S_IFBLK devices can be processed properly by fuse.
if(!(mode & S_IFMT)){
if(!isS3sync){
if(checkdir){
if(forcedir){
mode |= S_IFDIR;
}else{
if(meta.cend() != (iter = meta.find("Content-Type"))){
std::string strConType = (*iter).second;
// Leave just the mime type, remove any optional parameters (eg charset)
std::string::size_type pos = strConType.find(';');
if(std::string::npos != pos){
strConType.erase(pos);
}
if(strConType == "application/x-directory" || strConType == "httpd/unix-directory"){
// Nextcloud uses this MIME type for directory objects when mounting bucket as external Storage
mode |= S_IFDIR;
}else if(!strpath.empty() && '/' == *strpath.rbegin()){
if(strConType == "binary/octet-stream" || strConType == "application/octet-stream"){
mode |= S_IFDIR;
}else{
if(complement_stat){
// If complement lack stat mode, when the object has '/' character at end of name
// and content type is text/plain and the object's size is 0 or 1, it should be
// directory.
off_t size = get_size(meta);
if(strConType == "text/plain" && (0 == size || 1 == size)){
mode |= S_IFDIR;
}else{
mode |= S_IFREG;
}
}else{
mode |= S_IFREG;
}
}
}else{
mode |= S_IFREG;
}
}else{
mode |= S_IFREG;
}
}
}
// If complement lack stat mode, when it's mode is not set any permission,
// the object is added minimal mode only for read permission.
if(complement_stat && 0 == (mode & (S_IRWXU | S_IRWXG | S_IRWXO))){
mode |= (S_IRUSR | (0 == (mode & S_IFDIR) ? 0 : S_IXUSR));
}
}else{
if(!checkdir){
// cut dir/reg flag.
mode &= ~S_IFDIR;
mode &= ~S_IFREG;
}
}
}
return mode;
}
// [NOTE]
// Gets a only FMT bit in mode from meta headers.
// The processing is almost the same as get_mode().
// This function is intended to be used from get_object_attribute().
//
static mode_t convert_meta_to_mode_fmt(const headers_t& meta)
{
mode_t mode = 0;
bool isS3sync = false;
headers_t::const_iterator iter;
if(meta.cend() != (iter = meta.find("x-amz-meta-mode"))){
mode = get_mode((*iter).second.c_str());
}else if(meta.cend() != (iter = meta.find("x-amz-meta-permissions"))){ // for s3sync
mode = get_mode((*iter).second.c_str());
isS3sync = true;
}else if(meta.cend() != (iter = meta.find("x-amz-meta-goog-reserved-posix-mode"))){ // for GCS
mode = get_mode((*iter).second.c_str(), 8);
}
if(!(mode & S_IFMT)){
if(!isS3sync){
if(meta.cend() != (iter = meta.find("Content-Type"))){
std::string strConType = (*iter).second;
// Leave just the mime type, remove any optional parameters (eg charset)
std::string::size_type pos = strConType.find(';');
if(std::string::npos != pos){
strConType.erase(pos);
}
if(strConType == "application/x-directory" || strConType == "httpd/unix-directory"){
// Nextcloud uses this MIME type for directory objects when mounting bucket as external Storage
mode |= S_IFDIR;
}
}
}
}
return (mode & S_IFMT);
}
bool is_reg_fmt(const headers_t& meta)
{
return S_ISREG(convert_meta_to_mode_fmt(meta));
}
bool is_symlink_fmt(const headers_t& meta)
{
return S_ISLNK(convert_meta_to_mode_fmt(meta));
}
bool is_dir_fmt(const headers_t& meta)
{
return S_ISDIR(convert_meta_to_mode_fmt(meta));
}
// [NOTE]
// For directory types, detailed judgment is not possible.
// DIR_NORMAL is always returned.
//
// Objects uploaded using clients other than s3fs has a Content-Type
// of application/unknown and dose not have x-amz-meta-mode header.
// In this case, you can specify objtype_t as default_type.
//
objtype_t derive_object_type(const std::string& strpath, const headers_t& meta, objtype_t default_type)
{
mode_t mode = convert_meta_to_mode_fmt(meta);
if(S_ISDIR(mode)){
if('/' != *strpath.rbegin()){
return objtype_t::DIR_NOT_TERMINATE_SLASH;
}else if(std::string::npos != strpath.find("_$folder$", 0)){
return objtype_t::DIR_FOLDER_SUFFIX;
}else{
// [NOTE]
// It returns DIR_NORMAL, although it could be DIR_NOT_EXIST_OBJECT.
//
return objtype_t::DIR_NORMAL;
}
}else if(S_ISLNK(mode)){
return objtype_t::SYMLINK;
}else if(S_ISREG(mode)){
return objtype_t::FILE;
}else if(0 == mode){
// If the x-amz-meta-mode header is not present, mode is 0.
headers_t::const_iterator iter;
if(meta.cend() != (iter = meta.find("Content-Type"))){
std::string strConType = iter->second;
// Leave just the mime type, remove any optional parameters (eg charset)
std::string::size_type pos = strConType.find(';');
if(std::string::npos != pos){
strConType.erase(pos);
}
if(strConType == "application/unknown"){
return default_type;
}
}
}
return objtype_t::UNKNOWN;
}
uid_t get_uid(const char *s)
{
return static_cast<uid_t>(cvt_strtoofft(s, /*base=*/ 0));
}
uid_t get_uid(const headers_t& meta)
{
headers_t::const_iterator iter;
if(meta.cend() != (iter = meta.find("x-amz-meta-uid"))){
return get_uid((*iter).second.c_str());
}else if(meta.cend() != (iter = meta.find("x-amz-meta-owner"))){ // for s3sync
return get_uid((*iter).second.c_str());
}else if(meta.cend() != (iter = meta.find("x-amz-meta-goog-reserved-posix-uid"))){ // for GCS
return get_uid((*iter).second.c_str());
}else{
return geteuid();
}
}
gid_t get_gid(const char *s)
{
return static_cast<gid_t>(cvt_strtoofft(s, /*base=*/ 0));
}
gid_t get_gid(const headers_t& meta)
{
headers_t::const_iterator iter;
if(meta.cend() != (iter = meta.find("x-amz-meta-gid"))){
return get_gid((*iter).second.c_str());
}else if(meta.cend() != (iter = meta.find("x-amz-meta-group"))){ // for s3sync
return get_gid((*iter).second.c_str());
}else if(meta.cend() != (iter = meta.find("x-amz-meta-goog-reserved-posix-gid"))){ // for GCS
return get_gid((*iter).second.c_str());
}else{
return getegid();
}
}
blkcnt_t get_blocks(off_t size)
{
return (size / 512) + (0 == (size % 512) ? 0 : 1);
}
time_t cvtIAMExpireStringToTime(const char* s)
{
struct tm tm{};
if(!s){
return 0L;
}
s3fs_strptime(s, "%Y-%m-%dT%H:%M:%S", &tm);
return timegm(&tm); // GMT
}
time_t get_lastmodified(const char* s)
{
struct tm tm{};
if(!s){
return -1;
}
s3fs_strptime(s, "%a, %d %b %Y %H:%M:%S %Z", &tm);
return timegm(&tm); // GMT
}
time_t get_lastmodified(const headers_t& meta)
{
auto iter = meta.find("Last-Modified");
if(meta.cend() == iter){
return -1;
}
return get_lastmodified((*iter).second.c_str());
}
//
// Returns it whether it is an object with need checking in detail.
// If this function returns true, the object is possible to be directory
// and is needed checking detail(searching sub object).
//
bool is_need_check_obj_detail(const headers_t& meta)
{
headers_t::const_iterator iter;
// directory object is Content-Length as 0.
if(0 != get_size(meta)){
return false;
}
// if the object has x-amz-meta information, checking is no more.
if(meta.cend() != meta.find("x-amz-meta-mode") ||
meta.cend() != meta.find("x-amz-meta-mtime") ||
meta.cend() != meta.find("x-amz-meta-ctime") ||
meta.cend() != meta.find("x-amz-meta-atime") ||
meta.cend() != meta.find("x-amz-meta-uid") ||
meta.cend() != meta.find("x-amz-meta-gid") ||
meta.cend() != meta.find("x-amz-meta-owner") ||
meta.cend() != meta.find("x-amz-meta-group") ||
meta.cend() != meta.find("x-amz-meta-permissions") )
{
return false;
}
// if there is not Content-Type, or Content-Type is "x-directory",
// checking is no more.
if(meta.cend() == (iter = meta.find("Content-Type"))){
return false;
}
if("application/x-directory" == (*iter).second){
return false;
}
return true;
}
// [NOTE]
// If add_noexist is false and the key does not exist, it will not be added.
//
bool merge_headers(headers_t& base, const headers_t& additional, bool add_noexist)
{
bool added = false;
for(auto iter = additional.cbegin(); iter != additional.cend(); ++iter){
if(add_noexist || base.find(iter->first) != base.cend()){
base[iter->first] = iter->second;
added = true;
}
}
return added;
}
bool convert_header_to_stat(const std::string& strpath, const headers_t& meta, struct stat& stbuf, bool forcedir)
{
stbuf = {};
// set hard link count always 1
stbuf.st_nlink = 1; // see fuse FAQ
// mode
stbuf.st_mode = get_mode(meta, strpath, true, forcedir);
// blocks
if(S_ISREG(stbuf.st_mode)){
stbuf.st_blocks = get_blocks(stbuf.st_size);
}
stbuf.st_blksize = 4096;
// mtime
struct timespec mtime = get_mtime(meta);
if(mtime.tv_sec < 0){
mtime = {0, 0};
}
set_timespec_to_stat(stbuf, stat_time_type::MTIME, mtime);
// ctime
struct timespec ctime = get_ctime(meta);
if(ctime.tv_sec < 0){
ctime = {0, 0};
}
set_timespec_to_stat(stbuf, stat_time_type::CTIME, ctime);
// atime
struct timespec atime = get_atime(meta);
if(atime.tv_sec < 0){
atime = {0, 0};
}
set_timespec_to_stat(stbuf, stat_time_type::ATIME, atime);
// size
if(S_ISDIR(stbuf.st_mode)){
stbuf.st_size = 4096;
}else{
stbuf.st_size = get_size(meta);
}
// uid/gid
stbuf.st_uid = get_uid(meta);
stbuf.st_gid = get_gid(meta);
return true;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

70
src/metaheader.h Normal file
View File

@ -0,0 +1,70 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_METAHEADER_H_
#define S3FS_METAHEADER_H_
#include <map>
#include <string>
#include <sys/stat.h>
#include "types.h"
//-------------------------------------------------------------------
// headers_t
//-------------------------------------------------------------------
typedef std::map<std::string, std::string, case_insensitive_compare_func> headers_t;
//-------------------------------------------------------------------
// Functions
//-------------------------------------------------------------------
struct timespec get_mtime(const headers_t& meta, bool overcheck = true);
struct timespec get_ctime(const headers_t& meta, bool overcheck = true);
struct timespec get_atime(const headers_t& meta, bool overcheck = true);
off_t get_size(const char *s);
off_t get_size(const headers_t& meta);
mode_t get_mode(const char *s, int base = 0);
mode_t get_mode(const headers_t& meta, const std::string& strpath, bool checkdir = false, bool forcedir = false);
bool is_reg_fmt(const headers_t& meta);
bool is_symlink_fmt(const headers_t& meta);
bool is_dir_fmt(const headers_t& meta);
objtype_t derive_object_type(const std::string& strpath, const headers_t& meta, objtype_t default_type = objtype_t::UNKNOWN);
uid_t get_uid(const char *s);
uid_t get_uid(const headers_t& meta);
gid_t get_gid(const char *s);
gid_t get_gid(const headers_t& meta);
blkcnt_t get_blocks(off_t size);
time_t cvtIAMExpireStringToTime(const char* s);
time_t get_lastmodified(const char* s);
time_t get_lastmodified(const headers_t& meta);
bool is_need_check_obj_detail(const headers_t& meta);
bool merge_headers(headers_t& base, const headers_t& additional, bool add_noexist);
bool convert_header_to_stat(const std::string& strpath, const headers_t& meta, struct stat& stbuf, bool forcedir = false);
#endif // S3FS_METAHEADER_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

156
src/mpu_util.cpp Normal file
View File

@ -0,0 +1,156 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Takeshi Nakatani <ggtakec.com>
*
* 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.
*/
#include <cstdio>
#include <cstdlib>
#include <string>
#include "s3fs.h"
#include "s3fs_logger.h"
#include "mpu_util.h"
#include "curl.h"
#include "s3fs_xml.h"
#include "s3fs_auth.h"
#include "string_util.h"
#include "s3fs_threadreqs.h"
//-------------------------------------------------------------------
// Global variables
//-------------------------------------------------------------------
utility_incomp_type utility_mode = utility_incomp_type::NO_UTILITY_MODE;
//-------------------------------------------------------------------
// Functions
//-------------------------------------------------------------------
static void print_incomp_mpu_list(const incomp_mpu_list_t& list)
{
printf("\n");
printf("Lists the parts that have been uploaded for a specific multipart upload.\n");
printf("\n");
if(!list.empty()){
printf("---------------------------------------------------------------\n");
int cnt = 0;
for(auto iter = list.cbegin(); iter != list.cend(); ++iter, ++cnt){
printf(" Path : %s\n", (*iter).key.c_str());
printf(" UploadId : %s\n", (*iter).id.c_str());
printf(" Date : %s\n", (*iter).date.c_str());
printf("\n");
}
printf("---------------------------------------------------------------\n");
}else{
printf("There is no list.\n");
}
}
static bool abort_incomp_mpu_list(const incomp_mpu_list_t& list, time_t abort_time)
{
if(list.empty()){
return true;
}
time_t now_time = time(nullptr);
// do removing.
bool result = true;
for(auto iter = list.cbegin(); iter != list.cend(); ++iter){
const char* tpath = (*iter).key.c_str();
std::string upload_id = (*iter).id;
if(0 != abort_time){ // abort_time is 0, it means all.
time_t date = 0;
if(!get_unixtime_from_iso8601((*iter).date.c_str(), date)){
S3FS_PRN_DBG("date format is not ISO 8601 for %s multipart uploading object, skip this.", tpath);
continue;
}
if(now_time <= (date + abort_time)){
continue;
}
}
if(0 != abort_multipart_upload_request(tpath, upload_id)){
S3FS_PRN_EXIT("Failed to remove %s multipart uploading object.", tpath);
result = false;
}else{
printf("Succeed to remove %s multipart uploading object.\n", tpath);
}
}
return result;
}
int s3fs_utility_processing(time_t abort_time)
{
if(utility_incomp_type::NO_UTILITY_MODE == utility_mode){
return EXIT_FAILURE;
}
printf("\n*** s3fs run as utility mode.\n\n");
S3fsCurl s3fscurl;
std::string body;
int result = EXIT_SUCCESS;
if(0 != s3fscurl.MultipartListRequest(body)){
S3FS_PRN_EXIT("Could not get list multipart upload.\nThere is no incomplete multipart uploaded object in bucket.\n");
result = EXIT_FAILURE;
}else{
// parse result(incomplete multipart upload information)
S3FS_PRN_DBG("response body = {\n%s\n}", body.c_str());
std::unique_ptr<xmlDoc, decltype(&xmlFreeDoc)> doc(xmlReadMemory(body.c_str(), static_cast<int>(body.size()), "", nullptr, 0), xmlFreeDoc);
if(nullptr == doc){
S3FS_PRN_DBG("xmlReadMemory exited with error.");
result = EXIT_FAILURE;
}else{
// make incomplete uploads list
incomp_mpu_list_t list;
if(!get_incomp_mpu_list(doc.get(), list)){
S3FS_PRN_DBG("get_incomp_mpu_list exited with error.");
result = EXIT_FAILURE;
}else{
if(utility_incomp_type::INCOMP_TYPE_LIST == utility_mode){
// print list
print_incomp_mpu_list(list);
}else if(utility_incomp_type::INCOMP_TYPE_ABORT == utility_mode){
// remove
if(!abort_incomp_mpu_list(list, abort_time)){
S3FS_PRN_DBG("an error occurred during removal process.");
result = EXIT_FAILURE;
}
}
}
}
}
// ssl
s3fs_destroy_global_ssl();
return result;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

66
src/mpu_util.h Normal file
View File

@ -0,0 +1,66 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_MPU_UTIL_H_
#define S3FS_MPU_UTIL_H_
#include <cstdint>
#include <ctime>
#include <string>
#include <vector>
//-------------------------------------------------------------------
// Structure / Typedef
//-------------------------------------------------------------------
typedef struct incomplete_multipart_upload_info
{
std::string key;
std::string id;
std::string date;
}INCOMP_MPU_INFO;
typedef std::vector<INCOMP_MPU_INFO> incomp_mpu_list_t;
//-------------------------------------------------------------------
// enum for utility process mode
//-------------------------------------------------------------------
enum class utility_incomp_type : uint8_t {
NO_UTILITY_MODE = 0, // not utility mode
INCOMP_TYPE_LIST, // list of incomplete mpu
INCOMP_TYPE_ABORT // delete incomplete mpu
};
extern utility_incomp_type utility_mode;
//-------------------------------------------------------------------
// Functions
//-------------------------------------------------------------------
int s3fs_utility_processing(time_t abort_time);
#endif // S3FS_MPU_UTIL_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

View File

@ -1,7 +1,7 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright 2007-2008 Randy Rizun <rrizun@gmail.com>
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -18,15 +18,14 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <nss.h>
#include <pk11pub.h>
#include <hasht.h>
@ -35,253 +34,218 @@
#include <map>
#include "common.h"
#include "s3fs.h"
#include "s3fs_auth.h"
using namespace std;
#include "s3fs_logger.h"
//-------------------------------------------------------------------
// Utility Function for version
//-------------------------------------------------------------------
const char* s3fs_crypt_lib_name(void)
const char* s3fs_crypt_lib_name()
{
static const char version[] = "NSS";
static constexpr char version[] = "NSS";
return version;
return version;
}
//-------------------------------------------------------------------
// Utility Function for global init
//-------------------------------------------------------------------
bool s3fs_init_global_ssl(void)
bool s3fs_init_global_ssl()
{
NSS_Init(NULL);
NSS_NoDB_Init(NULL);
return true;
PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
if(SECSuccess != NSS_NoDB_Init(nullptr)){
S3FS_PRN_ERR("Failed NSS_NoDB_Init call.");
return false;
}
return true;
}
bool s3fs_destroy_global_ssl(void)
bool s3fs_destroy_global_ssl()
{
NSS_Shutdown();
PL_ArenaFinish();
PR_Cleanup();
return true;
NSS_Shutdown();
PL_ArenaFinish();
PR_Cleanup();
return true;
}
//-------------------------------------------------------------------
// Utility Function for crypt lock
//-------------------------------------------------------------------
bool s3fs_init_crypt_mutex(void)
bool s3fs_init_crypt_mutex()
{
return true;
return true;
}
bool s3fs_destroy_crypt_mutex(void)
bool s3fs_destroy_crypt_mutex()
{
return true;
return true;
}
//-------------------------------------------------------------------
// Utility Function for HMAC
//-------------------------------------------------------------------
static bool s3fs_HMAC_RAW(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned char** digest, unsigned int* digestlen, bool is_sha256)
static std::unique_ptr<unsigned char[]> s3fs_HMAC_RAW(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned int* digestlen, bool is_sha256)
{
if(!key || 0 >= keylen || !data || 0 >= datalen || !digest || !digestlen){
return false;
}
if(!key || !data || !digestlen){
return nullptr;
}
PK11SlotInfo* Slot;
PK11SymKey* pKey;
PK11Context* Context;
SECStatus SecStatus;
unsigned char tmpdigest[64];
SECItem KeySecItem = {siBuffer, reinterpret_cast<unsigned char*>(const_cast<void*>(key)), static_cast<unsigned int>(keylen)};
SECItem NullSecItem = {siBuffer, NULL, 0};
PK11SlotInfo* Slot;
PK11SymKey* pKey;
PK11Context* Context;
unsigned char tmpdigest[64];
SECItem KeySecItem = {siBuffer, reinterpret_cast<unsigned char*>(const_cast<void*>(key)), static_cast<unsigned int>(keylen)};
SECItem NullSecItem = {siBuffer, nullptr, 0};
if(NULL == (Slot = PK11_GetInternalKeySlot())){
return false;
}
if(NULL == (pKey = PK11_ImportSymKey(Slot, (is_sha256 ? CKM_SHA256_HMAC : CKM_SHA_1_HMAC), PK11_OriginUnwrap, CKA_SIGN, &KeySecItem, NULL))){
PK11_FreeSlot(Slot);
return false;
}
if(NULL == (Context = PK11_CreateContextBySymKey((is_sha256 ? CKM_SHA256_HMAC : CKM_SHA_1_HMAC), CKA_SIGN, pKey, &NullSecItem))){
PK11_FreeSymKey(pKey);
PK11_FreeSlot(Slot);
return false;
}
if(nullptr == (Slot = PK11_GetInternalKeySlot())){
return nullptr;
}
if(nullptr == (pKey = PK11_ImportSymKey(Slot, (is_sha256 ? CKM_SHA256_HMAC : CKM_SHA_1_HMAC), PK11_OriginUnwrap, CKA_SIGN, &KeySecItem, nullptr))){
PK11_FreeSlot(Slot);
return nullptr;
}
if(nullptr == (Context = PK11_CreateContextBySymKey((is_sha256 ? CKM_SHA256_HMAC : CKM_SHA_1_HMAC), CKA_SIGN, pKey, &NullSecItem))){
PK11_FreeSymKey(pKey);
PK11_FreeSlot(Slot);
return nullptr;
}
*digestlen = 0;
if(SECSuccess != (SecStatus = PK11_DigestBegin(Context)) ||
SECSuccess != (SecStatus = PK11_DigestOp(Context, data, datalen)) ||
SECSuccess != (SecStatus = PK11_DigestFinal(Context, tmpdigest, digestlen, sizeof(tmpdigest))) )
{
*digestlen = 0;
if(SECSuccess != PK11_DigestBegin(Context) ||
SECSuccess != PK11_DigestOp(Context, data, datalen) ||
SECSuccess != PK11_DigestFinal(Context, tmpdigest, digestlen, sizeof(tmpdigest)) )
{
PK11_DestroyContext(Context, PR_TRUE);
PK11_FreeSymKey(pKey);
PK11_FreeSlot(Slot);
return nullptr;
}
PK11_DestroyContext(Context, PR_TRUE);
PK11_FreeSymKey(pKey);
PK11_FreeSlot(Slot);
return false;
}
PK11_DestroyContext(Context, PR_TRUE);
PK11_FreeSymKey(pKey);
PK11_FreeSlot(Slot);
if(NULL == (*digest = (unsigned char*)malloc(*digestlen))){
return false;
}
memcpy(*digest, tmpdigest, *digestlen);
auto digest = std::make_unique<unsigned char[]>(*digestlen);
memcpy(digest.get(), tmpdigest, *digestlen);
return true;
return digest;
}
bool s3fs_HMAC(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned char** digest, unsigned int* digestlen)
std::unique_ptr<unsigned char[]> s3fs_HMAC(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned int* digestlen)
{
return s3fs_HMAC_RAW(key, keylen, data, datalen, digest, digestlen, false);
return s3fs_HMAC_RAW(key, keylen, data, datalen, digestlen, false);
}
bool s3fs_HMAC256(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned char** digest, unsigned int* digestlen)
std::unique_ptr<unsigned char[]> s3fs_HMAC256(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned int* digestlen)
{
return s3fs_HMAC_RAW(key, keylen, data, datalen, digest, digestlen, true);
return s3fs_HMAC_RAW(key, keylen, data, datalen, digestlen, true);
}
//-------------------------------------------------------------------
// Utility Function for MD5
//-------------------------------------------------------------------
size_t get_md5_digest_length(void)
bool s3fs_md5(const unsigned char* data, size_t datalen, md5_t* result)
{
return MD5_LENGTH;
PK11Context* md5ctx;
unsigned int md5outlen;
md5ctx = PK11_CreateDigestContext(SEC_OID_MD5);
PK11_DigestOp(md5ctx, data, datalen);
PK11_DigestFinal(md5ctx, result->data(), &md5outlen, result->size());
PK11_DestroyContext(md5ctx, PR_TRUE);
return true;
}
unsigned char* s3fs_md5hexsum(int fd, off_t start, ssize_t size)
bool s3fs_md5_fd(int fd, off_t start, off_t size, md5_t* result)
{
PK11Context* md5ctx;
unsigned char buf[512];
ssize_t bytes;
unsigned char* result;
unsigned int md5outlen;
PK11Context* md5ctx;
off_t bytes;
unsigned int md5outlen;
if(-1 == size){
struct stat st;
if(-1 == fstat(fd, &st)){
return NULL;
if(-1 == size){
struct stat st;
if(-1 == fstat(fd, &st)){
return false;
}
size = st.st_size;
}
size = static_cast<ssize_t>(st.st_size);
}
// seek to top of file.
if(-1 == lseek(fd, start, SEEK_SET)){
return NULL;
}
md5ctx = PK11_CreateDigestContext(SEC_OID_MD5);
memset(buf, 0, 512);
md5ctx = PK11_CreateDigestContext(SEC_OID_MD5);
for(ssize_t total = 0; total < size; total += bytes){
bytes = 512 < (size - total) ? 512 : (size - total);
bytes = read(fd, buf, bytes);
if(0 == bytes){
// end of file
break;
}else if(-1 == bytes){
// error
S3FS_PRN_ERR("file read error(%d)", errno);
return NULL;
for(off_t total = 0; total < size; total += bytes){
std::array<unsigned char, 512> buf;
bytes = std::min(static_cast<off_t>(buf.size()), (size - total));
bytes = pread(fd, buf.data(), bytes, start + total);
if(0 == bytes){
// end of file
break;
}else if(-1 == bytes){
// error
S3FS_PRN_ERR("file read error(%d)", errno);
PK11_DestroyContext(md5ctx, PR_TRUE);
return false;
}
PK11_DigestOp(md5ctx, buf.data(), bytes);
}
PK11_DigestOp(md5ctx, buf, bytes);
memset(buf, 0, 512);
}
if(NULL == (result = (unsigned char*)malloc(get_md5_digest_length()))){
PK11_DigestFinal(md5ctx, result->data(), &md5outlen, result->size());
PK11_DestroyContext(md5ctx, PR_TRUE);
return NULL;
}
PK11_DigestFinal(md5ctx, result, &md5outlen, get_md5_digest_length());
PK11_DestroyContext(md5ctx, PR_TRUE);
if(-1 == lseek(fd, start, SEEK_SET)){
free(result);
return NULL;
}
return result;
return true;
}
//-------------------------------------------------------------------
// Utility Function for SHA256
//-------------------------------------------------------------------
size_t get_sha256_digest_length(void)
bool s3fs_sha256(const unsigned char* data, size_t datalen, sha256_t* digest)
{
return SHA256_LENGTH;
}
PK11Context* sha256ctx;
unsigned int sha256outlen;
sha256ctx = PK11_CreateDigestContext(SEC_OID_SHA256);
bool s3fs_sha256(const unsigned char* data, unsigned int datalen, unsigned char** digest, unsigned int* digestlen)
{
(*digestlen) = static_cast<unsigned int>(get_sha256_digest_length());
if(NULL == ((*digest) = reinterpret_cast<unsigned char*>(malloc(*digestlen)))){
return false;
}
PK11Context* sha256ctx;
unsigned int sha256outlen;
sha256ctx = PK11_CreateDigestContext(SEC_OID_SHA256);
PK11_DigestOp(sha256ctx, data, datalen);
PK11_DigestFinal(sha256ctx, *digest, &sha256outlen, *digestlen);
PK11_DestroyContext(sha256ctx, PR_TRUE);
*digestlen = sha256outlen;
return true;
}
unsigned char* s3fs_sha256hexsum(int fd, off_t start, ssize_t size)
{
PK11Context* sha256ctx;
unsigned char buf[512];
ssize_t bytes;
unsigned char* result;
unsigned int sha256outlen;
if(-1 == size){
struct stat st;
if(-1 == fstat(fd, &st)){
return NULL;
}
size = static_cast<ssize_t>(st.st_size);
}
// seek to top of file.
if(-1 == lseek(fd, start, SEEK_SET)){
return NULL;
}
memset(buf, 0, 512);
sha256ctx = PK11_CreateDigestContext(SEC_OID_SHA256);
for(ssize_t total = 0; total < size; total += bytes){
bytes = 512 < (size - total) ? 512 : (size - total);
bytes = read(fd, buf, bytes);
if(0 == bytes){
// end of file
break;
}else if(-1 == bytes){
// error
S3FS_PRN_ERR("file read error(%d)", errno);
PK11_DestroyContext(sha256ctx, PR_TRUE);
return NULL;
}
PK11_DigestOp(sha256ctx, buf, bytes);
memset(buf, 0, 512);
}
if(NULL == (result = (unsigned char*)malloc(get_sha256_digest_length()))){
PK11_DigestOp(sha256ctx, data, datalen);
PK11_DigestFinal(sha256ctx, digest->data(), &sha256outlen, digest->size());
PK11_DestroyContext(sha256ctx, PR_TRUE);
return NULL;
}
PK11_DigestFinal(sha256ctx, result, &sha256outlen, get_sha256_digest_length());
PK11_DestroyContext(sha256ctx, PR_TRUE);
if(-1 == lseek(fd, start, SEEK_SET)){
free(result);
return NULL;
}
return true;
}
return result;
bool s3fs_sha256_fd(int fd, off_t start, off_t size, sha256_t* result)
{
PK11Context* sha256ctx;
off_t bytes;
unsigned int sha256outlen;
if(-1 == size){
struct stat st;
if(-1 == fstat(fd, &st)){
return false;
}
size = st.st_size;
}
sha256ctx = PK11_CreateDigestContext(SEC_OID_SHA256);
for(off_t total = 0; total < size; total += bytes){
std::array<unsigned char, 512> buf;
bytes = std::min(static_cast<off_t>(buf.size()), (size - total));
bytes = pread(fd, buf.data(), bytes, start + total);
if(0 == bytes){
// end of file
break;
}else if(-1 == bytes){
// error
S3FS_PRN_ERR("file read error(%d)", errno);
PK11_DestroyContext(sha256ctx, PR_TRUE);
return false;
}
PK11_DigestOp(sha256ctx, buf.data(), bytes);
}
PK11_DigestFinal(sha256ctx, result->data(), &sha256outlen, result->size());
PK11_DestroyContext(sha256ctx, PR_TRUE);
return true;
}
/*
@ -289,6 +253,6 @@ unsigned char* s3fs_sha256hexsum(int fd, off_t start, ssize_t size)
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

View File

@ -1,7 +1,7 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright 2007-2008 Randy Rizun <rrizun@gmail.com>
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -18,57 +18,60 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
#ifdef __clang__
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
#include <cstdio>
#include <cstdlib>
#include <cerrno>
#include <memory>
#include <mutex>
#include <unistd.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <string>
#include <map>
#include <thread>
#include "common.h"
#include "s3fs_auth.h"
using namespace std;
#include "s3fs_logger.h"
//-------------------------------------------------------------------
// Utility Function for version
//-------------------------------------------------------------------
const char* s3fs_crypt_lib_name(void)
const char* s3fs_crypt_lib_name()
{
static const char version[] = "OpenSSL";
static constexpr char version[] = "OpenSSL";
return version;
return version;
}
//-------------------------------------------------------------------
// Utility Function for global init
//-------------------------------------------------------------------
bool s3fs_init_global_ssl(void)
bool s3fs_init_global_ssl()
{
ERR_load_crypto_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
return true;
ERR_load_crypto_strings();
// [NOTE]
// OpenSSL 3.0 loads error strings automatically so these functions are not needed.
//
#ifndef USE_OPENSSL_30
ERR_load_BIO_strings();
#endif
OpenSSL_add_all_algorithms();
return true;
}
bool s3fs_destroy_global_ssl(void)
bool s3fs_destroy_global_ssl()
{
EVP_cleanup();
ERR_free_strings();
return true;
EVP_cleanup();
ERR_free_strings();
return true;
}
//-------------------------------------------------------------------
@ -77,276 +80,298 @@ bool s3fs_destroy_global_ssl(void)
// internal use struct for openssl
struct CRYPTO_dynlock_value
{
pthread_mutex_t dyn_mutex;
std::mutex dyn_mutex;
};
static pthread_mutex_t* s3fs_crypt_mutex = NULL;
static std::unique_ptr<std::mutex[]> s3fs_crypt_mutex;
static void s3fs_crypt_mutex_lock(int mode, int pos, const char* file, int line) __attribute__ ((unused)) NO_THREAD_SAFETY_ANALYSIS;
static void s3fs_crypt_mutex_lock(int mode, int pos, const char* file, int line)
{
if(s3fs_crypt_mutex){
if(mode & CRYPTO_LOCK){
pthread_mutex_lock(&s3fs_crypt_mutex[pos]);
}else{
pthread_mutex_unlock(&s3fs_crypt_mutex[pos]);
if(s3fs_crypt_mutex){
if(mode & CRYPTO_LOCK){
s3fs_crypt_mutex[pos].lock();
}else{
s3fs_crypt_mutex[pos].unlock();
}
}
}
}
static unsigned long s3fs_crypt_get_threadid(void)
static unsigned long s3fs_crypt_get_threadid() __attribute__ ((unused));
static unsigned long s3fs_crypt_get_threadid()
{
// For FreeBSD etc, some system's pthread_t is structure pointer.
// Then we use cast like C style(not C++) instead of ifdef.
return (unsigned long)(pthread_self());
return static_cast<unsigned long>(std::hash<std::thread::id>()(std::this_thread::get_id()));
}
static struct CRYPTO_dynlock_value* s3fs_dyn_crypt_mutex(const char* file, int line) __attribute__ ((unused));
static struct CRYPTO_dynlock_value* s3fs_dyn_crypt_mutex(const char* file, int line)
{
struct CRYPTO_dynlock_value* dyndata;
if(NULL == (dyndata = static_cast<struct CRYPTO_dynlock_value*>(malloc(sizeof(struct CRYPTO_dynlock_value))))){
S3FS_PRN_CRIT("Could not allocate memory for CRYPTO_dynlock_value");
return NULL;
}
pthread_mutex_init(&(dyndata->dyn_mutex), NULL);
return dyndata;
return new CRYPTO_dynlock_value();
}
static void s3fs_dyn_crypt_mutex_lock(int mode, struct CRYPTO_dynlock_value* dyndata, const char* file, int line) __attribute__ ((unused)) NO_THREAD_SAFETY_ANALYSIS;
static void s3fs_dyn_crypt_mutex_lock(int mode, struct CRYPTO_dynlock_value* dyndata, const char* file, int line)
{
if(dyndata){
if(mode & CRYPTO_LOCK){
pthread_mutex_lock(&(dyndata->dyn_mutex));
}else{
pthread_mutex_unlock(&(dyndata->dyn_mutex));
if(dyndata){
if(mode & CRYPTO_LOCK){
dyndata->dyn_mutex.lock();
}else{
dyndata->dyn_mutex.unlock();
}
}
}
}
static void s3fs_destroy_dyn_crypt_mutex(struct CRYPTO_dynlock_value* dyndata, const char* file, int line) __attribute__ ((unused));
static void s3fs_destroy_dyn_crypt_mutex(struct CRYPTO_dynlock_value* dyndata, const char* file, int line)
{
if(dyndata){
pthread_mutex_destroy(&(dyndata->dyn_mutex));
free(dyndata);
}
delete dyndata;
}
bool s3fs_init_crypt_mutex(void)
bool s3fs_init_crypt_mutex()
{
if(s3fs_crypt_mutex){
S3FS_PRN_DBG("s3fs_crypt_mutex is not NULL, destroy it.");
if(!s3fs_destroy_crypt_mutex()){
S3FS_PRN_ERR("Failed to s3fs_crypt_mutex");
return false;
if(s3fs_crypt_mutex){
S3FS_PRN_DBG("s3fs_crypt_mutex is not nullptr, destroy it.");
// cppcheck-suppress unmatchedSuppression
// cppcheck-suppress knownConditionTrueFalse
if(!s3fs_destroy_crypt_mutex()){
S3FS_PRN_ERR("Failed to s3fs_crypt_mutex");
return false;
}
}
}
if(NULL == (s3fs_crypt_mutex = static_cast<pthread_mutex_t*>(malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t))))){
S3FS_PRN_CRIT("Could not allocate memory for s3fs_crypt_mutex");
return false;
}
for(int cnt = 0; cnt < CRYPTO_num_locks(); cnt++){
pthread_mutex_init(&s3fs_crypt_mutex[cnt], NULL);
}
// static lock
CRYPTO_set_locking_callback(s3fs_crypt_mutex_lock);
CRYPTO_set_id_callback(s3fs_crypt_get_threadid);
// dynamic lock
CRYPTO_set_dynlock_create_callback(s3fs_dyn_crypt_mutex);
CRYPTO_set_dynlock_lock_callback(s3fs_dyn_crypt_mutex_lock);
CRYPTO_set_dynlock_destroy_callback(s3fs_destroy_dyn_crypt_mutex);
s3fs_crypt_mutex = std::make_unique<std::mutex[]>(CRYPTO_num_locks());
// static lock
CRYPTO_set_locking_callback(s3fs_crypt_mutex_lock);
CRYPTO_set_id_callback(s3fs_crypt_get_threadid);
// dynamic lock
CRYPTO_set_dynlock_create_callback(s3fs_dyn_crypt_mutex);
CRYPTO_set_dynlock_lock_callback(s3fs_dyn_crypt_mutex_lock);
CRYPTO_set_dynlock_destroy_callback(s3fs_destroy_dyn_crypt_mutex);
return true;
return true;
}
bool s3fs_destroy_crypt_mutex(void)
bool s3fs_destroy_crypt_mutex()
{
if(!s3fs_crypt_mutex){
if(!s3fs_crypt_mutex){
return true;
}
CRYPTO_set_dynlock_destroy_callback(nullptr);
CRYPTO_set_dynlock_lock_callback(nullptr);
CRYPTO_set_dynlock_create_callback(nullptr);
CRYPTO_set_id_callback(nullptr);
CRYPTO_set_locking_callback(nullptr);
CRYPTO_cleanup_all_ex_data();
s3fs_crypt_mutex.reset();
return true;
}
CRYPTO_set_dynlock_destroy_callback(NULL);
CRYPTO_set_dynlock_lock_callback(NULL);
CRYPTO_set_dynlock_create_callback(NULL);
CRYPTO_set_id_callback(NULL);
CRYPTO_set_locking_callback(NULL);
for(int cnt = 0; cnt < CRYPTO_num_locks(); cnt++){
pthread_mutex_destroy(&s3fs_crypt_mutex[cnt]);
}
CRYPTO_cleanup_all_ex_data();
free(s3fs_crypt_mutex);
s3fs_crypt_mutex = NULL;
return true;
}
//-------------------------------------------------------------------
// Utility Function for HMAC
//-------------------------------------------------------------------
static bool s3fs_HMAC_RAW(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned char** digest, unsigned int* digestlen, bool is_sha256)
static std::unique_ptr<unsigned char[]> s3fs_HMAC_RAW(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned int* digestlen, bool is_sha256)
{
if(!key || 0 >= keylen || !data || 0 >= datalen || !digest || !digestlen){
return false;
}
(*digestlen) = EVP_MAX_MD_SIZE * sizeof(unsigned char);
if(NULL == ((*digest) = (unsigned char*)malloc(*digestlen))){
return false;
}
if(is_sha256){
HMAC(EVP_sha256(), key, keylen, data, datalen, *digest, digestlen);
}else{
HMAC(EVP_sha1(), key, keylen, data, datalen, *digest, digestlen);
}
return true;
}
bool s3fs_HMAC(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned char** digest, unsigned int* digestlen)
{
return s3fs_HMAC_RAW(key, keylen, data, datalen, digest, digestlen, false);
}
bool s3fs_HMAC256(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned char** digest, unsigned int* digestlen)
{
return s3fs_HMAC_RAW(key, keylen, data, datalen, digest, digestlen, true);
}
//-------------------------------------------------------------------
// Utility Function for MD5
//-------------------------------------------------------------------
size_t get_md5_digest_length(void)
{
return MD5_DIGEST_LENGTH;
}
unsigned char* s3fs_md5hexsum(int fd, off_t start, ssize_t size)
{
MD5_CTX md5ctx;
char buf[512];
ssize_t bytes;
unsigned char* result;
if(-1 == size){
struct stat st;
if(-1 == fstat(fd, &st)){
return NULL;
if(!key || !data || !digestlen){
return nullptr;
}
size = static_cast<ssize_t>(st.st_size);
}
// seek to top of file.
if(-1 == lseek(fd, start, SEEK_SET)){
return NULL;
}
memset(buf, 0, 512);
MD5_Init(&md5ctx);
for(ssize_t total = 0; total < size; total += bytes){
bytes = 512 < (size - total) ? 512 : (size - total);
bytes = read(fd, buf, bytes);
if(0 == bytes){
// end of file
break;
}else if(-1 == bytes){
// error
S3FS_PRN_ERR("file read error(%d)", errno);
return NULL;
(*digestlen) = EVP_MAX_MD_SIZE * sizeof(unsigned char);
auto digest = std::make_unique<unsigned char[]>(*digestlen);
if(is_sha256){
HMAC(EVP_sha256(), key, static_cast<int>(keylen), data, datalen, digest.get(), digestlen);
}else{
HMAC(EVP_sha1(), key, static_cast<int>(keylen), data, datalen, digest.get(), digestlen);
}
MD5_Update(&md5ctx, buf, bytes);
memset(buf, 0, 512);
}
if(NULL == (result = (unsigned char*)malloc(get_md5_digest_length()))){
return NULL;
}
MD5_Final(result, &md5ctx);
if(-1 == lseek(fd, start, SEEK_SET)){
free(result);
return NULL;
}
return result;
return digest;
}
std::unique_ptr<unsigned char[]> s3fs_HMAC(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned int* digestlen)
{
return s3fs_HMAC_RAW(key, keylen, data, datalen, digestlen, false);
}
std::unique_ptr<unsigned char[]> s3fs_HMAC256(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned int* digestlen)
{
return s3fs_HMAC_RAW(key, keylen, data, datalen, digestlen, true);
}
#ifdef USE_OPENSSL_30
//-------------------------------------------------------------------
// Utility Function for MD5 (OpenSSL >= 3.0)
//-------------------------------------------------------------------
// [NOTE]
// OpenSSL 3.0 deprecated the MD5_*** low-level encryption functions,
// so we should use the high-level EVP API instead.
//
bool s3fs_md5(const unsigned char* data, size_t datalen, md5_t* digest)
{
auto digestlen = static_cast<unsigned int>(digest->size());
const EVP_MD* md = EVP_get_digestbyname("md5");
EVP_MD_CTX* mdctx = EVP_MD_CTX_create();
EVP_DigestInit_ex(mdctx, md, nullptr);
EVP_DigestUpdate(mdctx, data, datalen);
EVP_DigestFinal_ex(mdctx, digest->data(), &digestlen);
EVP_MD_CTX_destroy(mdctx);
return true;
}
bool s3fs_md5_fd(int fd, off_t start, off_t size, md5_t* result)
{
auto md5_digest_len = static_cast<unsigned int>(result->size());
off_t bytes;
if(-1 == size){
struct stat st;
if(-1 == fstat(fd, &st)){
return false;
}
size = st.st_size;
}
// instead of MD5_Init
std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)> mdctx(EVP_MD_CTX_new(), EVP_MD_CTX_free);
EVP_DigestInit_ex(mdctx.get(), EVP_md5(), nullptr);
for(off_t total = 0; total < size; total += bytes){
std::array<char, 512> buf;
bytes = std::min(static_cast<off_t>(buf.size()), (size - total));
bytes = pread(fd, buf.data(), bytes, start + total);
if(0 == bytes){
// end of file
break;
}else if(-1 == bytes){
// error
S3FS_PRN_ERR("file read error(%d)", errno);
return false;
}
// instead of MD5_Update
EVP_DigestUpdate(mdctx.get(), buf.data(), bytes);
}
// instead of MD5_Final
EVP_DigestFinal_ex(mdctx.get(), result->data(), &md5_digest_len);
return true;
}
#else
//-------------------------------------------------------------------
// Utility Function for MD5 (OpenSSL < 3.0)
//-------------------------------------------------------------------
// TODO: Does this fail on OpenSSL < 3.0 and we need to use MD5_CTX functions?
bool s3fs_md5(const unsigned char* data, size_t datalen, md5_t* digest)
{
unsigned int digestlen = digest->size();
const EVP_MD* md = EVP_get_digestbyname("md5");
EVP_MD_CTX* mdctx = EVP_MD_CTX_create();
EVP_DigestInit_ex(mdctx, md, nullptr);
EVP_DigestUpdate(mdctx, data, datalen);
EVP_DigestFinal_ex(mdctx, digest->data(), &digestlen);
EVP_MD_CTX_destroy(mdctx);
return true;
}
bool s3fs_md5_fd(int fd, off_t start, off_t size, md5_t* result)
{
MD5_CTX md5ctx;
off_t bytes;
if(-1 == size){
struct stat st;
if(-1 == fstat(fd, &st)){
return false;
}
size = st.st_size;
}
MD5_Init(&md5ctx);
for(off_t total = 0; total < size; total += bytes){
std::array<char, 512> buf;
bytes = std::min(static_cast<off_t>(buf.size()), (size - total));
bytes = pread(fd, buf.data(), bytes, start + total);
if(0 == bytes){
// end of file
break;
}else if(-1 == bytes){
// error
S3FS_PRN_ERR("file read error(%d)", errno);
return false;
}
MD5_Update(&md5ctx, buf.data(), bytes);
}
MD5_Final(result->data(), &md5ctx);
return true;
}
#endif
//-------------------------------------------------------------------
// Utility Function for SHA256
//-------------------------------------------------------------------
size_t get_sha256_digest_length(void)
bool s3fs_sha256(const unsigned char* data, size_t datalen, sha256_t* digest)
{
return SHA256_DIGEST_LENGTH;
const EVP_MD* md = EVP_get_digestbyname("sha256");
EVP_MD_CTX* mdctx = EVP_MD_CTX_create();
EVP_DigestInit_ex(mdctx, md, nullptr);
EVP_DigestUpdate(mdctx, data, datalen);
auto digestlen = static_cast<unsigned int>(digest->size());
EVP_DigestFinal_ex(mdctx, digest->data(), &digestlen);
EVP_MD_CTX_destroy(mdctx);
return true;
}
bool s3fs_sha256(const unsigned char* data, unsigned int datalen, unsigned char** digest, unsigned int* digestlen)
bool s3fs_sha256_fd(int fd, off_t start, off_t size, sha256_t* result)
{
(*digestlen) = EVP_MAX_MD_SIZE * sizeof(unsigned char);
if(NULL == ((*digest) = reinterpret_cast<unsigned char*>(malloc(*digestlen)))){
return false;
}
const EVP_MD* md = EVP_get_digestbyname("sha256");
EVP_MD_CTX* sha256ctx;
off_t bytes;
const EVP_MD* md = EVP_get_digestbyname("sha256");
EVP_MD_CTX* mdctx = EVP_MD_CTX_create();
EVP_DigestInit_ex(mdctx, md, NULL);
EVP_DigestUpdate(mdctx, data, datalen);
EVP_DigestFinal_ex(mdctx, *digest, digestlen);
EVP_MD_CTX_destroy(mdctx);
return true;
}
unsigned char* s3fs_sha256hexsum(int fd, off_t start, ssize_t size)
{
const EVP_MD* md = EVP_get_digestbyname("sha256");
EVP_MD_CTX* sha256ctx;
char buf[512];
ssize_t bytes;
unsigned char* result;
if(-1 == size){
struct stat st;
if(-1 == fstat(fd, &st)){
return NULL;
if(-1 == fd){
return false;
}
size = static_cast<ssize_t>(st.st_size);
}
// seek to top of file.
if(-1 == lseek(fd, start, SEEK_SET)){
return NULL;
}
sha256ctx = EVP_MD_CTX_create();
EVP_DigestInit_ex(sha256ctx, md, NULL);
memset(buf, 0, 512);
for(ssize_t total = 0; total < size; total += bytes){
bytes = 512 < (size - total) ? 512 : (size - total);
bytes = read(fd, buf, bytes);
if(0 == bytes){
// end of file
break;
}else if(-1 == bytes){
// error
S3FS_PRN_ERR("file read error(%d)", errno);
EVP_MD_CTX_destroy(sha256ctx);
return NULL;
if(-1 == size){
struct stat st;
if(-1 == fstat(fd, &st)){
S3FS_PRN_ERR("fstat error(%d)", errno);
return false;
}
size = st.st_size;
}
EVP_DigestUpdate(sha256ctx, buf, bytes);
memset(buf, 0, 512);
}
if(NULL == (result = (unsigned char*)malloc(get_sha256_digest_length()))){
sha256ctx = EVP_MD_CTX_create();
EVP_DigestInit_ex(sha256ctx, md, nullptr);
for(off_t total = 0; total < size; total += bytes){
std::array<char, 512> buf;
bytes = std::min(static_cast<off_t>(buf.size()), (size - total));
bytes = pread(fd, buf.data(), bytes, start + total);
if(0 == bytes){
// end of file
break;
}else if(-1 == bytes){
// error
S3FS_PRN_ERR("file read error(%d)", errno);
EVP_MD_CTX_destroy(sha256ctx);
return false;
}
EVP_DigestUpdate(sha256ctx, buf.data(), bytes);
}
EVP_DigestFinal_ex(sha256ctx, result->data(), nullptr);
EVP_MD_CTX_destroy(sha256ctx);
return NULL;
}
EVP_DigestFinal_ex(sha256ctx, result, NULL);
EVP_MD_CTX_destroy(sha256ctx);
if(-1 == lseek(fd, start, SEEK_SET)){
free(result);
return NULL;
}
return result;
return true;
}
/*
@ -354,6 +379,6 @@ unsigned char* s3fs_sha256hexsum(int fd, off_t start, ssize_t size)
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

124
src/psemaphore.h Normal file
View File

@ -0,0 +1,124 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_SEMAPHORE_H_
#define S3FS_SEMAPHORE_H_
//-------------------------------------------------------------------
// Class Semaphore
//-------------------------------------------------------------------
#if __cplusplus >= 202002L
#include <semaphore>
typedef std::counting_semaphore<INT_MAX> Semaphore;
#else
// portability wrapper for sem_t since macOS does not implement it
#ifdef __APPLE__
#include <dispatch/dispatch.h>
class Semaphore
{
public:
explicit Semaphore(int value) : value(value), sem(dispatch_semaphore_create(value)) {}
~Semaphore()
{
// macOS cannot destroy a semaphore with posts less than the initializer
for(int i = 0; i < value; ++i){
release();
}
dispatch_release(sem);
}
Semaphore(const Semaphore&) = delete;
Semaphore(Semaphore&&) = delete;
Semaphore& operator=(const Semaphore&) = delete;
Semaphore& operator=(Semaphore&&) = delete;
void acquire() { dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); }
bool try_acquire()
{
if(0 == dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW)){
return true;
}else{
return false;
}
}
void release() { dispatch_semaphore_signal(sem); }
private:
int value;
dispatch_semaphore_t sem;
};
#else
#include <cerrno>
#include <semaphore.h>
class Semaphore
{
public:
explicit Semaphore(int value) { sem_init(&mutex, 0, value); }
~Semaphore() { sem_destroy(&mutex); }
Semaphore(const Semaphore&) = delete;
Semaphore(Semaphore&&) = delete;
Semaphore& operator=(const Semaphore&) = delete;
Semaphore& operator=(Semaphore&&) = delete;
void acquire()
{
int r;
do {
r = sem_wait(&mutex);
} while (r == -1 && errno == EINTR);
}
bool try_acquire()
{
int result;
do{
result = sem_trywait(&mutex);
}while(result == -1 && errno == EINTR);
return (0 == result);
}
void release() { sem_post(&mutex); }
private:
sem_t mutex;
};
#endif
#endif
#endif // S3FS_SEMAPHORE_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright 2007-2008 Randy Rizun <rrizun@gmail.com>
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -17,80 +17,29 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef S3FS_S3_H_
#define S3FS_S3_H_
#ifndef S3FS_S3FS_H_
#define S3FS_S3FS_H_
#define FUSE_USE_VERSION 26
#define FIVE_GB 5368709120LL
#include <fuse.h>
#define S3FS_FUSE_EXIT() { \
struct fuse_context* pcxt = fuse_get_context(); \
if(pcxt){ \
fuse_exit(pcxt->fuse); \
} \
}
#define S3FS_FUSE_EXIT() \
do{ \
struct fuse_context* pcxt = fuse_get_context(); \
if(pcxt){ \
fuse_exit(pcxt->fuse); \
} \
}while(0)
//
// s3fs use many small allocated chunk in heap area for
// stats cache and parsing xml, etc. The OS may decide
// that giving this little memory back to the kernel
// will cause too much overhead and delay the operation.
// So s3fs calls malloc_trim function to really get the
// memory back. Following macros is prepared for that
// your system does not have it.
//
// Address of gratitude, this workaround quotes a document
// of libxml2.
// http://xmlsoft.org/xmlmem.html
//
#ifdef HAVE_MALLOC_TRIM
#include <malloc.h>
#define DISPWARN_MALLOCTRIM(str)
#define S3FS_MALLOCTRIM(pad) malloc_trim(pad)
#define S3FS_XMLFREEDOC(doc) \
{ \
xmlFreeDoc(doc); \
S3FS_MALLOCTRIM(0); \
}
#define S3FS_XMLFREE(ptr) \
{ \
xmlFree(ptr); \
S3FS_MALLOCTRIM(0); \
}
#define S3FS_XMLXPATHFREECONTEXT(ctx) \
{ \
xmlXPathFreeContext(ctx); \
S3FS_MALLOCTRIM(0); \
}
#define S3FS_XMLXPATHFREEOBJECT(obj) \
{ \
xmlXPathFreeObject(obj); \
S3FS_MALLOCTRIM(0); \
}
#else // HAVE_MALLOC_TRIM
#define DISPWARN_MALLOCTRIM(str) \
fprintf(stderr, "Warning: %s without malloc_trim is possibility of the use memory increase.\n", program_name.c_str())
#define S3FS_MALLOCTRIM(pad)
#define S3FS_XMLFREEDOC(doc) xmlFreeDoc(doc)
#define S3FS_XMLFREE(ptr) xmlFree(ptr)
#define S3FS_XMLXPATHFREECONTEXT(ctx) xmlXPathFreeContext(ctx)
#define S3FS_XMLXPATHFREEOBJECT(obj) xmlXPathFreeObject(obj)
#endif // HAVE_MALLOC_TRIM
#endif // S3FS_S3_H_
#endif // S3FS_S3FS_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

View File

@ -1,7 +1,7 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright 2007-2008 Randy Rizun <rrizun@gmail.com>
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -17,12 +17,18 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef S3FS_AUTH_H_
#define S3FS_AUTH_H_
#include <array>
#include <memory>
#include <string>
#include <sys/types.h>
typedef std::array<unsigned char, 16> md5_t;
typedef std::array<unsigned char, 32> sha256_t;
//-------------------------------------------------------------------
// Utility functions for Authentication
//-------------------------------------------------------------------
@ -30,24 +36,22 @@
// in common_auth.cpp
//
std::string s3fs_get_content_md5(int fd);
std::string s3fs_md5sum(int fd, off_t start, ssize_t size);
std::string s3fs_sha256sum(int fd, off_t start, ssize_t size);
std::string s3fs_sha256_hex_fd(int fd, off_t start, off_t size);
//
// in xxxxxx_auth.cpp
//
const char* s3fs_crypt_lib_name(void);
bool s3fs_init_global_ssl(void);
bool s3fs_destroy_global_ssl(void);
bool s3fs_init_crypt_mutex(void);
bool s3fs_destroy_crypt_mutex(void);
bool s3fs_HMAC(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned char** digest, unsigned int* digestlen);
bool s3fs_HMAC256(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned char** digest, unsigned int* digestlen);
size_t get_md5_digest_length(void);
unsigned char* s3fs_md5hexsum(int fd, off_t start, ssize_t size);
bool s3fs_sha256(const unsigned char* data, unsigned int datalen, unsigned char** digest, unsigned int* digestlen);
size_t get_sha256_digest_length(void);
unsigned char* s3fs_sha256hexsum(int fd, off_t start, ssize_t size);
const char* s3fs_crypt_lib_name();
bool s3fs_init_global_ssl();
bool s3fs_destroy_global_ssl();
bool s3fs_init_crypt_mutex();
bool s3fs_destroy_crypt_mutex();
std::unique_ptr<unsigned char[]> s3fs_HMAC(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned int* digestlen);
std::unique_ptr<unsigned char[]> s3fs_HMAC256(const void* key, size_t keylen, const unsigned char* data, size_t datalen, unsigned int* digestlen);
bool s3fs_md5(const unsigned char* data, size_t datalen, md5_t* result);
bool s3fs_md5_fd(int fd, off_t start, off_t size, md5_t* result);
bool s3fs_sha256(const unsigned char* data, size_t datalen, sha256_t* digest);
bool s3fs_sha256_fd(int fd, off_t start, off_t size, sha256_t* result);
#endif // S3FS_AUTH_H_
@ -56,6 +60,6 @@ unsigned char* s3fs_sha256hexsum(int fd, off_t start, ssize_t size);
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

1601
src/s3fs_cred.cpp Normal file

File diff suppressed because it is too large Load Diff

201
src/s3fs_cred.h Normal file
View File

@ -0,0 +1,201 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_CRED_H_
#define S3FS_CRED_H_
#include <map>
#include <mutex>
#include <string>
#include "common.h"
#include "s3fs_extcred.h"
#include "types.h"
//----------------------------------------------
// Typedefs
//----------------------------------------------
typedef std::map<std::string, std::string> iamcredmap_t;
//------------------------------------------------
// class S3fsCred
//------------------------------------------------
// This is a class for operating and managing Credentials(accesskey,
// secret key, tokens, etc.) used by S3fs.
// Operations related to Credentials are aggregated in this class.
//
// cppcheck-suppress ctuOneDefinitionRuleViolation ; for stub in test_curl_util.cpp
class S3fsCred
{
private:
static constexpr char ALLBUCKET_FIELDS_TYPE[] = ""; // special key for mapping(This name is absolutely not used as a bucket name)
static constexpr char KEYVAL_FIELDS_TYPE[] = "\t"; // special key for mapping(This name is absolutely not used as a bucket name)
static constexpr char AWS_ACCESSKEYID[] = "AWSAccessKeyId";
static constexpr char AWS_SECRETKEY[] = "AWSSecretKey";
static constexpr int IAM_EXPIRE_MERGING = 20 * 60; // update timing
static constexpr char ECS_IAM_ENV_VAR[] = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI";
static constexpr char IAMCRED_ACCESSKEYID[] = "AccessKeyId";
static constexpr char IAMCRED_SECRETACCESSKEY[] = "SecretAccessKey";
static constexpr char IAMCRED_ROLEARN[] = "RoleArn";
static std::string bucket_name;
mutable std::mutex token_lock;
std::string passwd_file;
std::string aws_profile;
bool load_iamrole;
std::string AWSAccessKeyId GUARDED_BY(token_lock);
std::string AWSSecretAccessKey GUARDED_BY(token_lock);
std::string AWSAccessToken GUARDED_BY(token_lock);
time_t AWSAccessTokenExpire GUARDED_BY(token_lock);
bool is_ecs;
bool is_use_session_token;
bool is_ibm_iam_auth;
std::string IAM_cred_url;
int IAM_api_version GUARDED_BY(token_lock);
std::string IAMv2_api_token GUARDED_BY(token_lock);
size_t IAM_field_count;
std::string IAM_token_field;
std::string IAM_expiry_field;
std::string IAM_role GUARDED_BY(token_lock);
bool set_builtin_cred_opts; // true if options other than "credlib" is set
std::string credlib; // credlib(name or path)
std::string credlib_opts; // options for credlib
void* hExtCredLib;
fp_VersionS3fsCredential pFuncCredVersion;
fp_InitS3fsCredential pFuncCredInit;
fp_FreeS3fsCredential pFuncCredFree;
fp_UpdateS3fsCredential pFuncCredUpdate;
public:
static constexpr char IAMv2_token_url[] = "http://169.254.169.254/latest/api/token";
static constexpr int IAMv2_token_ttl = 21600;
static constexpr char IAMv2_token_ttl_hdr[] = "X-aws-ec2-metadata-token-ttl-seconds";
static constexpr char IAMv2_token_hdr[] = "X-aws-ec2-metadata-token";
private:
static bool ParseIAMRoleFromMetaDataResponse(const char* response, std::string& rolename);
bool SetS3fsPasswdFile(const char* file);
bool IsSetPasswdFile() const;
bool SetAwsProfileName(const char* profile_name);
bool SetIAMRoleMetadataType(bool flag);
bool SetAccessKey(const char* AccessKeyId, const char* SecretAccessKey) REQUIRES(S3fsCred::token_lock);
bool SetAccessKeyWithSessionToken(const char* AccessKeyId, const char* SecretAccessKey, const char * SessionToken) REQUIRES(S3fsCred::token_lock);
bool IsSetAccessKeys() const REQUIRES(S3fsCred::token_lock);
bool SetIsECS(bool flag);
bool SetIsUseSessionToken(bool flag);
bool SetIsIBMIAMAuth(bool flag);
int SetIMDSVersionHasLock(int version) REQUIRES(S3fsCred::token_lock);
int SetIMDSVersion(int version)
{
const std::lock_guard<std::mutex> lock(token_lock);
return SetIMDSVersionHasLock(version);
}
int GetIMDSVersion() const REQUIRES(S3fsCred::token_lock);
bool SetIAMv2APITokenHasLock(const std::string& token) REQUIRES(S3fsCred::token_lock);
const std::string& GetIAMv2APIToken() const REQUIRES(S3fsCred::token_lock);
bool SetIAMRole(const char* role) REQUIRES(S3fsCred::token_lock);
const std::string& GetIAMRoleHasLock() const REQUIRES(S3fsCred::token_lock);
const std::string& GetIAMRole() const
{
const std::lock_guard<std::mutex> lock(token_lock);
return GetIAMRoleHasLock();
}
bool IsSetIAMRole() const REQUIRES(S3fsCred::token_lock);
size_t SetIAMFieldCount(size_t field_count);
std::string SetIAMCredentialsURL(const char* url);
std::string SetIAMTokenField(const char* token_field);
std::string SetIAMExpiryField(const char* expiry_field);
bool IsReadableS3fsPasswdFile() const;
bool CheckS3fsPasswdFilePerms();
bool ParseS3fsPasswdFile(bucketkvmap_t& resmap);
bool ReadS3fsPasswdFile() REQUIRES(S3fsCred::token_lock);
static int CheckS3fsCredentialAwsFormat(const kvmap_t& kvmap, std::string& access_key_id, std::string& secret_access_key);
bool ReadAwsCredentialFile(const std::string &filename) REQUIRES(S3fsCred::token_lock);
bool InitialS3fsCredentials() REQUIRES(S3fsCred::token_lock);
bool ParseIAMCredentialResponse(const char* response, iamcredmap_t& keyval) const;
bool GetIAMCredentialsURL(std::string& url, bool check_iam_role) REQUIRES(S3fsCred::token_lock);
bool LoadIAMCredentials() REQUIRES(S3fsCred::token_lock);
bool SetIAMCredentials(const char* response) REQUIRES(S3fsCred::token_lock);
bool SetIAMRoleFromMetaData(const char* response);
bool SetExtCredLib(const char* arg);
bool IsSetExtCredLib() const;
bool SetExtCredLibOpts(const char* args);
bool IsSetExtCredLibOpts() const;
bool InitExtCredLib();
bool LoadExtCredLib();
bool UnloadExtCredLib();
bool UpdateExtCredentials() REQUIRES(S3fsCred::token_lock);
static bool CheckForbiddenBucketParams();
public:
static bool SetBucket(const std::string& bucket);
static const std::string& GetBucket();
S3fsCred();
~S3fsCred();
S3fsCred(const S3fsCred&) = delete;
S3fsCred(S3fsCred&&) = delete;
S3fsCred& operator=(const S3fsCred&) = delete;
S3fsCred& operator=(S3fsCred&&) = delete;
bool IsIBMIAMAuth() const { return is_ibm_iam_auth; }
bool LoadIAMRoleFromMetaData();
bool CheckIAMCredentialUpdate(std::string* access_key_id = nullptr, std::string* secret_access_key = nullptr, std::string* access_token = nullptr);
const char* GetCredFuncVersion(bool detail) const;
int DetectParam(const char* arg);
bool CheckAllParams();
};
#endif // S3FS_CRED_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

144
src/s3fs_extcred.h Normal file
View File

@ -0,0 +1,144 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Takeshi Nakatani <ggtakec@gmail.com>
*
* 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.
*/
#ifndef S3FS_EXTCRED_H_
#define S3FS_EXTCRED_H_
//-------------------------------------------------------------------
// Attributes(weak) : use only in s3fs-fuse internally
//-------------------------------------------------------------------
// [NOTE]
// This macro is only used inside s3fs-fuse.
// External projects that utilize this header file substitute empty
//values as follows:
//
#ifndef S3FS_FUNCATTR_WEAK
#define S3FS_FUNCATTR_WEAK
#endif
extern "C" {
//-------------------------------------------------------------------
// Prototype for External Credential 4 functions
//-------------------------------------------------------------------
//
// [Required] VersionS3fsCredential
//
// Returns the library name and version as a string.
//
extern const char* VersionS3fsCredential(bool detail) S3FS_FUNCATTR_WEAK;
//
// [Optional] InitS3fsCredential
//
// A function that does the necessary initialization after the library is
// loaded. This function is called only once immediately after loading the
// library.
// If there is a required initialization inside the library, implement it.
// Implementation of this function is optional and not required. If not
// implemented, it will not be called.
//
// const char* popts : String passed with the credlib_opts option. If the
// credlib_opts option is not specified, nullptr will be
// passed.
// char** pperrstr : pperrstr is used to pass the error message to the
// caller when an error occurs.
// If this pointer is not nullptr, you can allocate memory
// and set an error message to it. The allocated memory
// area is freed by the caller.
//
extern bool InitS3fsCredential(const char* popts, char** pperrstr) S3FS_FUNCATTR_WEAK;
//
// [Optional] FreeS3fsCredential
//
// A function that is called only once just before the library is unloaded.
// If there is a required discard process in the library, implement it.
// Implementation of this feature is optional and not required.
// If not implemented, it will not be called.
//
// char** pperrstr : pperrstr is used to pass the error message to the
// caller when an error occurs.
// If this pointer is not nullptr, you can allocate memory
// and set an error message to it. The allocated memory
// area is freed by the caller.
//
extern bool FreeS3fsCredential(char** pperrstr) S3FS_FUNCATTR_WEAK;
//
// [Required] UpdateS3fsCredential
//
// A function that updates the token.
//
// char** ppaccess_key_id : Allocate and set "Access Key ID" string
// area to *ppaccess_key_id.
// char** ppsecret_access_key : Allocate and set "Access Secret Key ID"
// string area to *ppsecret_access_key.
// char** ppaccess_token : Allocate and set "Token" string area to
// *ppaccess_token.
// long long* ptoken_expire : Set token expire time(time_t) value to
// *ptoken_expire.
// This is essentially a time_t* variable.
// To avoid system differences about time_t
// size, long long* is used.
// When setting the value, cast from time_t
// to long long to set the value.
// char** pperrstr : pperrstr is used to pass the error message to the
// caller when an error occurs.
//
// For all argument of the character string pointer(char **) set the
// allocated string area. The allocated area is freed by the caller.
//
extern bool UpdateS3fsCredential(char** ppaccess_key_id, char** ppsecret_access_key, char** ppaccess_token, long long* ptoken_expire, char** pperrstr) S3FS_FUNCATTR_WEAK;
//---------------------------------------------------------
// Typedef Prototype function
//---------------------------------------------------------
//
// const char* VersionS3fsCredential()
//
typedef const char* (*fp_VersionS3fsCredential)(bool detail);
//
// bool InitS3fsCredential(char** pperrstr)
//
typedef bool (*fp_InitS3fsCredential)(const char* popts, char** pperrstr);
//
// bool FreeS3fsCredential(char** pperrstr)
//
typedef bool (*fp_FreeS3fsCredential)(char** pperrstr);
//
// bool UpdateS3fsCredential(char** ppaccess_key_id, char** ppsecret_access_key, char** ppaccess_token, long long* ptoken_expire, char** pperrstr)
//
typedef bool (*fp_UpdateS3fsCredential)(char** ppaccess_key_id, char** ppsecret_access_key, char** ppaccess_token, long long* ptoken_expire, char** pperrstr);
} // extern "C"
#endif // S3FS_EXTCRED_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

58
src/s3fs_global.cpp Normal file
View File

@ -0,0 +1,58 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Takeshi Nakatani <ggtakec.com>
*
* 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.
*/
#include <string>
#include "common.h"
//-------------------------------------------------------------------
// Global variables
//-------------------------------------------------------------------
bool foreground = false;
bool nomultipart = false;
bool pathrequeststyle = false;
bool complement_stat = false;
bool noxmlns = false;
std::string program_name;
std::string service_path = "/";
std::string s3host = "https://s3.amazonaws.com";
std::string region = "us-east-1";
std::string cipher_suites;
std::string instance_name;
std::atomic<long long unsigned> num_requests_head_object;
std::atomic<long long unsigned> num_requests_put_object;
std::atomic<long long unsigned> num_requests_get_object;
std::atomic<long long unsigned> num_requests_delete_object;
std::atomic<long long unsigned> num_requests_list_bucket;
std::atomic<long long unsigned> num_requests_mpu_initiate;
std::atomic<long long unsigned> num_requests_mpu_complete;
std::atomic<long long unsigned> num_requests_mpu_abort;
std::atomic<long long unsigned> num_requests_mpu_upload_part;
std::atomic<long long unsigned> num_requests_mpu_copy_part;
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

675
src/s3fs_help.cpp Normal file
View File

@ -0,0 +1,675 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Takeshi Nakatani <ggtakec.com>
*
* 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.
*/
#include <cstdio>
#include <string>
#include "common.h"
#include "s3fs_help.h"
#include "s3fs_auth.h"
//-------------------------------------------------------------------
// Contents
//-------------------------------------------------------------------
static constexpr char help_string[] =
"\n"
"Mount an Amazon S3 bucket as a file system.\n"
"\n"
"Usage:\n"
" mounting\n"
" s3fs bucket[:/path] mountpoint [options]\n"
" s3fs mountpoint [options (must specify bucket= option)]\n"
"\n"
" unmounting\n"
" umount mountpoint\n"
"\n"
" General forms for s3fs and FUSE/mount options:\n"
" -o opt[,opt...]\n"
" -o opt [-o opt] ...\n"
"\n"
" utility mode (remove interrupted multipart uploading objects)\n"
" s3fs --incomplete-mpu-list (-u) bucket\n"
" s3fs --incomplete-mpu-abort[=all | =<date format>] bucket\n"
"\n"
"s3fs Options:\n"
"\n"
" Most s3fs options are given in the form where \"opt\" is:\n"
"\n"
" <option_name>=<option_value>\n"
"\n"
" bucket\n"
" - if it is not specified bucket name (and path) in command line,\n"
" must specify this option after -o option for bucket name.\n"
"\n"
" default_acl (default=\"private\")\n"
" - the default canned acl to apply to all written s3 objects,\n"
" e.g., private, public-read. see\n"
" https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl\n"
" for the full list of canned ACLs\n"
"\n"
" retries (default=\"5\")\n"
" - number of times to retry a failed S3 transaction\n"
"\n"
" tmpdir (default=\"/tmp\")\n"
" - local folder for temporary files.\n"
"\n"
" use_cache (default=\"\" which means disabled)\n"
" - local folder to use for local file cache\n"
"\n"
" check_cache_dir_exist (default is disable)\n"
" - if use_cache is set, check if the cache directory exists.\n"
" If this option is not specified, it will be created at runtime\n"
" when the cache directory does not exist.\n"
"\n"
" del_cache (delete local file cache)\n"
" - delete local file cache when s3fs starts and exits.\n"
"\n"
" storage_class (default=\"standard\")\n"
" - store object with specified storage class. Possible values:\n"
" standard, standard_ia, onezone_ia, reduced_redundancy,\n"
" intelligent_tiering, glacier, glacier_ir, and deep_archive.\n"
"\n"
" use_rrs (default is disable)\n"
" - use Amazon's Reduced Redundancy Storage.\n"
" this option can not be specified with use_sse.\n"
" (can specify use_rrs=1 for old version)\n"
" this option has been replaced by new storage_class option.\n"
"\n"
" use_sse (default is disable)\n"
" - Specify three type Amazon's Server-Site Encryption: SSE-S3,\n"
" SSE-C or SSE-KMS. SSE-S3 uses Amazon S3-managed encryption\n"
" keys, SSE-C uses customer-provided encryption keys, and\n"
" SSE-KMS uses the master key which you manage in AWS KMS.\n"
" You can specify \"use_sse\" or \"use_sse=1\" enables SSE-S3\n"
" type (use_sse=1 is old type parameter).\n"
" Case of setting SSE-C, you can specify \"use_sse=custom\",\n"
" \"use_sse=custom:<custom key file path>\" or\n"
" \"use_sse=<custom key file path>\" (only <custom key file path>\n"
" specified is old type parameter). You can use \"c\" for\n"
" short \"custom\".\n"
" The custom key file must be 600 permission. The file can\n"
" have some lines, each line is one SSE-C key. The first line\n"
" in file is used as Customer-Provided Encryption Keys for\n"
" uploading and changing headers etc. If there are some keys\n"
" after first line, those are used downloading object which\n"
" are encrypted by not first key. So that, you can keep all\n"
" SSE-C keys in file, that is SSE-C key history.\n"
" If you specify \"custom\" (\"c\") without file path, you\n"
" need to set custom key by load_sse_c option or AWSSSECKEYS\n"
" environment. (AWSSSECKEYS environment has some SSE-C keys\n"
" with \":\" separator.) This option is used to decide the\n"
" SSE type. So that if you do not want to encrypt a object\n"
" object at uploading, but you need to decrypt encrypted\n"
" object at downloading, you can use load_sse_c option instead\n"
" of this option.\n"
" For setting SSE-KMS, specify \"use_sse=kmsid\" or\n"
" \"use_sse=kmsid:<kms id>\". You can use \"k\" for short \"kmsid\".\n"
" If you san specify SSE-KMS type with your <kms id> in AWS\n"
" KMS, you can set it after \"kmsid:\" (or \"k:\"). If you\n"
" specify only \"kmsid\" (\"k\"), you need to set AWSSSEKMSID\n"
" environment which value is <kms id>. You must be careful\n"
" about that you can not use the KMS id which is not same EC2\n"
" region.\n"
" Additionally, if you specify SSE-KMS, your endpoints must use\n"
" Secure Sockets Layer(SSL) or Transport Layer Security(TLS).\n"
"\n"
" load_sse_c - specify SSE-C keys\n"
" Specify the custom-provided encryption keys file path for decrypting\n"
" at downloading.\n"
" If you use the custom-provided encryption key at uploading, you\n"
" specify with \"use_sse=custom\". The file has many lines, one line\n"
" means one custom key. So that you can keep all SSE-C keys in file,\n"
" that is SSE-C key history. AWSSSECKEYS environment is as same as this\n"
" file contents.\n"
"\n"
" public_bucket (default=\"\" which means disabled)\n"
" - anonymously mount a public bucket when set to 1, ignores the \n"
" $HOME/.passwd-s3fs and /etc/passwd-s3fs files.\n"
" S3 does not allow copy object api for anonymous users, then\n"
" s3fs sets nocopyapi option automatically when public_bucket=1\n"
" option is specified.\n"
"\n"
" passwd_file (default=\"\")\n"
" - specify which s3fs password file to use\n"
"\n"
" ahbe_conf (default=\"\" which means disabled)\n"
" - This option specifies the configuration file path which\n"
" file is the additional HTTP header by file (object) extension.\n"
" The configuration file format is below:\n"
" -----------\n"
" line = [file suffix or regex] HTTP-header [HTTP-values]\n"
" file suffix = file (object) suffix, if this field is empty,\n"
" it means \"reg:(.*)\".(=all object).\n"
" regex = regular expression to match the file (object) path.\n"
" this type starts with \"reg:\" prefix.\n"
" HTTP-header = additional HTTP header name\n"
" HTTP-values = additional HTTP header value\n"
" -----------\n"
" Sample:\n"
" -----------\n"
" .gz Content-Encoding gzip\n"
" .Z Content-Encoding compress\n"
" reg:^/MYDIR/(.*)[.]t2$ Content-Encoding text2\n"
" -----------\n"
" A sample configuration file is uploaded in \"test\" directory.\n"
" If you specify this option for set \"Content-Encoding\" HTTP \n"
" header, please take care for RFC 2616.\n"
"\n"
" profile (default=\"default\")\n"
" - Choose a profile from ${HOME}/.aws/credentials to authenticate\n"
" against S3. Note that this format matches the AWS CLI format and\n"
" differs from the s3fs passwd format.\n"
"\n"
" connect_timeout (default=\"300\" seconds)\n"
" - time to wait for connection before giving up\n"
"\n"
" readwrite_timeout (default=\"120\" seconds)\n"
" - time to wait between read/write activity before giving up\n"
"\n"
" list_object_max_keys (default=\"1000\")\n"
" - specify the maximum number of keys returned by S3 list object\n"
" API. The default is 1000. you can set this value to 1000 or more.\n"
"\n"
" max_stat_cache_size (default=\"100,000\" entries (about 40MB))\n"
" - maximum number of entries in the stat cache, and this maximum is\n"
" also treated as the number of symbolic link cache.\n"
"\n"
" stat_cache_expire (default is 900))\n"
" - specify expire time (seconds) for entries in the stat cache.\n"
" This expire time indicates the time since stat cached.\n"
"\n"
" stat_cache_interval_expire (default is 900)\n"
" - specify expire time (seconds) for entries in the stat cache.\n"
" This expire time is based on the time from the last access time\n"
" of the stat cache. This option is exclusive with stat_cache_expire,\n"
" and is left for compatibility with older versions.\n"
"\n"
" enable_negative_cache (default is enabled negative cache)\n"
" - This option will keep non-existence of objects in a stat cache.\n"
" When this negative cache is enabled, it will not process extra\n"
" HeadObject requests to search for non-existent objects, improving\n"
" performance.\n"
" This feature is enabled by default, so there is no need to specify\n"
" it.\n"
"\n"
" disable_negative_cache (default is enabled negative cache)\n"
" - By default, s3fs keeps non-existent objects in the stat cache.\n"
" This option disables this negative caching.\n"
" This prevents delays in updates due to cache retention.\n"
" However, it may increase the number of HeadObject requests to check\n"
" if an object exists, which may decrease performance.\n"
"\n"
" no_check_certificate\n"
" - server certificate won't be checked against the available \n"
" certificate authorities.\n"
"\n"
" ssl_verify_hostname (default=\"2\")\n"
" - When 0, do not verify the SSL certificate against the hostname.\n"
"\n"
" ssl_client_cert (default=\"\")\n"
" - Specify an SSL client certificate.\n"
" Specify this optional parameter in the following format:\n"
" \"<SSL Cert>[:<Cert Type>[:<Private Key>[:<Key Type>\n"
" [:<Password>]]]]\"\n"
" <SSL Cert>: Client certificate.\n"
" Specify the file path or NickName(for NSS, etc.).\n"
" <Cert Type>: Type of certificate, default is \"PEM\"(optional).\n"
" <Private Key>: Certificate's private key file(optional).\n"
" <Key Type>: Type of private key, default is \"PEM\"(optional).\n"
" <Password>: Passphrase of the private key(optional).\n"
" It is also possible to omit this value and specify\n"
" it using the environment variable\n"
" \"S3FS_SSL_PRIVKEY_PASSWORD\".\n"
"\n"
" nodnscache (disable DNS cache)\n"
" - s3fs is always using DNS cache, this option make DNS cache disable.\n"
"\n"
" nosscache (disable SSL session cache)\n"
" - s3fs is always using SSL session cache, this option make SSL \n"
" session cache disable.\n"
"\n"
" multipart_size (default=\"10\")\n"
" - part size, in MB, for each multipart request.\n"
" The minimum value is 5 MB and the maximum value is 5 GB.\n"
"\n"
" multipart_copy_size (default=\"512\")\n"
" - part size, in MB, for each multipart copy request, used for\n"
" renames and mixupload.\n"
" The minimum value is 5 MB and the maximum value is 5 GB.\n"
" Must be at least 512 MB to copy the maximum 5 TB object size\n"
" but lower values may improve performance.\n"
"\n"
" max_dirty_data (default=\"5120\")\n"
" - flush dirty data to S3 after a certain number of MB written.\n"
" The minimum value is 50 MB. -1 value means disable.\n"
" Cannot be used with nomixupload.\n"
"\n"
" bucket_size (default=maximum long unsigned integer value)\n"
" - The size of the bucket with which the corresponding\n"
" elements of the statvfs structure will be filled. The option\n"
" argument is an integer optionally followed by a\n"
" multiplicative suffix (GB, GiB, TB, TiB, PB, PiB,\n"
" EB, EiB) (no spaces in between). If no suffix is supplied,\n"
" bytes are assumed; eg: 20000000, 30GB, 45TiB. Note that\n"
" s3fs does not compute the actual volume size (too\n"
" expensive): by default it will assume the maximum possible\n"
" size; however, since this may confuse other software which\n"
" uses s3fs, the advertised bucket size can be set with this\n"
" option.\n"
"\n"
" ensure_diskfree (default 0)\n"
" - sets MB to ensure disk free space. This option means the\n"
" threshold of free space size on disk which is used for the\n"
" cache file by s3fs. s3fs makes file for\n"
" downloading, uploading and caching files. If the disk free\n"
" space is smaller than this value, s3fs do not use disk space\n"
" as possible in exchange for the performance.\n"
"\n"
" free_space_ratio (default=\"10\")\n"
" - sets min free space ratio of the disk.\n"
" The value of this option can be between 0 and 100. It will control\n"
" the size of the cache according to this ratio to ensure that the\n"
" idle ratio of the disk is greater than this value.\n"
" For example, when the disk space is 50GB, the default value will\n"
" ensure that the disk will reserve at least 50GB * 10%% = 5GB of\n"
" remaining space.\n"
"\n"
" multipart_threshold (default=\"25\")\n"
" - threshold, in MB, to use multipart upload instead of\n"
" single-part. Must be at least 5 MB.\n"
"\n"
" singlepart_copy_limit (default=\"512\")\n"
" - maximum size, in MB, of a single-part copy before trying \n"
" multipart copy.\n"
"\n"
" host (default=\"https://s3.amazonaws.com\")\n"
" - Set a non-Amazon host, e.g., https://example.com.\n"
"\n"
" servicepath (default=\"/\")\n"
" - Set a service path when the non-Amazon host requires a prefix.\n"
"\n"
" url (default=\"https://s3.amazonaws.com\")\n"
" - sets the url to use to access Amazon S3. If you want to use HTTP,\n"
" then you can set \"url=http://s3.amazonaws.com\".\n"
" If you do not use https, please specify the URL with the url\n"
" option.\n"
"\n"
" region (default=\"us-east-1\")\n"
" - sets the region to use on signature version 4\n"
" If this option is not specified, s3fs uses \"us-east-1\" region as\n"
" the default. If the s3fs could not connect to the region specified\n"
" by this option, s3fs could not run. But if you do not specify this\n"
" option, and if you can not connect with the default region, s3fs\n"
" will retry to automatically connect to the other region. So s3fs\n"
" can know the correct region name, because s3fs can find it in an\n"
" error from the S3 server.\n"
" You can also specify the legacy -o endpoint which means the same thing.\n"
"\n"
" sigv2 (default is signature version 4 falling back to version 2)\n"
" - sets signing AWS requests by using only signature version 2\n"
"\n"
" sigv4 (default is signature version 4 falling back to version 2)\n"
" - sets signing AWS requests by using only signature version 4\n"
"\n"
" mp_umask (default is \"0000\")\n"
" - sets umask for the mount point directory.\n"
" If allow_other option is not set, s3fs allows access to the mount\n"
" point only to the owner. In the opposite case s3fs allows access\n"
" to all users as the default. But if you set the allow_other with\n"
" this option, you can control the permissions of the\n"
" mount point by this option like umask.\n"
"\n"
" umask (default is \"0000\")\n"
" - sets umask for files under the mountpoint. This can allow\n"
" users other than the mounting user to read and write to files\n"
" that they did not create.\n"
"\n"
" nomultipart (disable multipart uploads)\n"
"\n"
" streamupload (default is disable)\n"
" - Enable stream upload.\n"
" If this option is enabled, a sequential upload will be performed\n"
" in parallel with the write from the part that has been written\n"
" during a multipart upload.\n"
" This is expected to give better performance than other upload\n"
" functions.\n"
" Note that this option is still experimental and may change in the\n"
" future.\n"
"\n"
" max_thread_count (default is \"10\")\n"
" - This value is the maximum number of parallel requests to be\n"
" sent, and the number of parallel processes for head requests,\n"
" multipart uploads and stream uploads.\n"
" Worker threads will be started to process requests according to\n"
" this value.\n"
"\n"
" enable_content_md5 (default is disable)\n"
" - Allow S3 server to check data integrity of uploads via the\n"
" Content-MD5 header. This can add CPU overhead to transfers.\n"
"\n"
" enable_unsigned_payload (default is disable)\n"
" - Do not calculate Content-SHA256 for PutObject and UploadPart\n"
" payloads. This can reduce CPU overhead to transfers.\n"
"\n"
" ecs (default is disable)\n"
" - This option instructs s3fs to query the ECS container credential\n"
" metadata address instead of the instance metadata address.\n"
"\n"
" iam_role (default is no IAM role)\n"
" - This option requires the IAM role name or \"auto\". If you specify\n"
" \"auto\", s3fs will automatically use the IAM role names that are set\n"
" to an instance. If you specify this option without any argument, it\n"
" is the same as that you have specified the \"auto\".\n"
"\n"
" imdsv1only (default is to use IMDSv2 with fallback to v1)\n"
" - AWS instance metadata service, used with IAM role authentication,\n"
" supports the use of an API token. If you're using an IAM role\n"
" in an environment that does not support IMDSv2, setting this flag\n"
" will skip retrieval and usage of the API token when retrieving\n"
" IAM credentials.\n"
"\n"
" ibm_iam_auth (default is not using IBM IAM authentication)\n"
" - This option instructs s3fs to use IBM IAM authentication.\n"
" In this mode, the AWSAccessKey and AWSSecretKey will be used as\n"
" IBM's Service-Instance-ID and APIKey, respectively.\n"
"\n"
" ibm_iam_endpoint (default is https://iam.cloud.ibm.com)\n"
" - sets the URL to use for IBM IAM authentication.\n"
"\n"
" credlib (default=\"\" which means disabled)\n"
" - Specifies the shared library that handles the credentials\n"
" containing the authentication token.\n"
" If this option is specified, the specified credential and token\n"
" processing provided by the shared library ant will be performed\n"
" instead of the built-in credential processing.\n"
" This option cannot be specified with passwd_file, profile,\n"
" use_session_token, ecs, ibm_iam_auth, ibm_iam_endpoint, imdsv1only\n"
" and iam_role option.\n"
"\n"
" credlib_opts (default=\"\" which means disabled)\n"
" - Specifies the options to pass when the shared library specified\n"
" in credlib is loaded and then initialized.\n"
" For the string specified in this option, specify the string defined\n"
" by the shared library.\n"
"\n"
" use_xattr (default is not handling the extended attribute)\n"
" Enable to handle the extended attribute (xattrs).\n"
" If you set this option, you can use the extended attribute.\n"
" For example, encfs and ecryptfs need to support the extended attribute.\n"
" Notice: if s3fs handles the extended attribute, s3fs can not work to\n"
" copy command with preserve=mode.\n"
"\n"
" noxmlns (disable registering xml name space)\n"
" disable registering xml name space for response of \n"
" ListBucketResult and ListVersionsResult etc. Default name \n"
" space is looked up from \"http://s3.amazonaws.com/doc/2006-03-01\".\n"
" This option should not be specified now, because s3fs looks up\n"
" xmlns automatically after v1.66.\n"
"\n"
" nomixupload (disable copy in multipart uploads)\n"
" Disable to use PUT (copy api) when multipart uploading large size objects.\n"
" By default, when doing multipart upload, the range of unchanged data\n"
" will use PUT (copy api) whenever possible.\n"
" When nocopyapi or norenameapi is specified, use of PUT (copy api) is\n"
" invalidated even if this option is not specified.\n"
"\n"
" nocopyapi (for other incomplete compatibility object storage)\n"
" Enable compatibility with S3-like APIs which do not support\n"
" PUT (copy api).\n"
" If you set this option, s3fs do not use PUT with \n"
" \"x-amz-copy-source\" (copy api). Because traffic is increased\n"
" 2-3 times by this option, we do not recommend this.\n"
"\n"
" norenameapi (for other incomplete compatibility object storage)\n"
" Enable compatibility with S3-like APIs which do not support\n"
" PUT (copy api).\n"
" This option is a subset of nocopyapi option. The nocopyapi\n"
" option does not use copy-api for all command (ex. chmod, chown,\n"
" touch, mv, etc), but this option does not use copy-api for\n"
" only rename command (ex. mv). If this option is specified with\n"
" nocopyapi, then s3fs ignores it.\n"
"\n"
" use_path_request_style (use legacy API calling style)\n"
" Enable compatibility with S3-like APIs which do not support\n"
" the virtual-host request style, by using the older path request\n"
" style.\n"
"\n"
" listobjectsv2 (use ListObjectsV2)\n"
" Issue ListObjectsV2 instead of ListObjects, useful on object\n"
" stores without ListObjects support.\n"
"\n"
" noua (suppress User-Agent header)\n"
" Usually s3fs outputs of the User-Agent in \"s3fs/<version> (commit\n"
" hash <hash>; <using ssl library name>)\" format.\n"
" If this option is specified, s3fs suppresses the output of the\n"
" User-Agent.\n"
"\n"
" cipher_suites\n"
" Customize the list of TLS cipher suites.\n"
" Expects a colon separated list of cipher suite names.\n"
" A list of available cipher suites, depending on your TLS engine,\n"
" can be found on the CURL library documentation:\n"
" https://curl.haxx.se/docs/ssl-ciphers.html\n"
"\n"
" instance_name - The instance name of the current s3fs mountpoint.\n"
" This name will be added to logging messages and user agent headers sent by s3fs.\n"
"\n"
" complement_stat (complement lack of file/directory mode)\n"
" s3fs complements lack of information about file/directory mode\n"
" if a file or a directory object does not have x-amz-meta-mode\n"
" header. As default, s3fs does not complements stat information\n"
" for a object, then the object will not be able to be allowed to\n"
" list/modify.\n"
"\n"
" compat_dir (enable support of alternative directory names)\n"
" s3fs supports two different naming schemas \"dir/\" and\n"
" \"dir\" to map directory names to S3 objects and\n"
" vice versa by default. As a third variant, directories can be\n"
" determined indirectly if there is a file object with a path (e.g.\n"
" \"/dir/file\") but without the parent directory.\n"
" This option enables a fourth variant, \"dir_$folder$\", created by\n"
" older applications.\n"
" \n"
" S3fs uses only the first schema \"dir/\" to create S3 objects for\n"
" directories."
" \n"
" The support for these different naming schemas causes an increased\n"
" communication effort.\n"
"\n"
" use_wtf8 - support arbitrary file system encoding.\n"
" S3 requires all object names to be valid UTF-8. But some\n"
" clients, notably Windows NFS clients, use their own encoding.\n"
" This option re-encodes invalid UTF-8 object names into valid\n"
" UTF-8 by mapping offending codes into a 'private' codepage of the\n"
" Unicode set.\n"
" Useful on clients not using UTF-8 as their file system encoding.\n"
"\n"
" use_session_token - indicate that session token should be provided.\n"
" If credentials are provided by environment variables this switch\n"
" forces presence check of AWSSESSIONTOKEN variable.\n"
" Otherwise an error is returned.\n"
"\n"
" requester_pays (default is disable)\n"
" This option instructs s3fs to enable requests involving\n"
" Requester Pays buckets.\n"
" It includes the 'x-amz-request-payer=requester' entry in the\n"
" request header.\n"
"\n"
" mime (default is \"/etc/mime.types\")\n"
" Specify the path of the mime.types file.\n"
" If this option is not specified, the existence of \"/etc/mime.types\"\n"
" is checked, and that file is loaded as mime information.\n"
" If this file does not exist on macOS, then \"/etc/apache2/mime.types\"\n"
" is checked as well.\n"
"\n"
" proxy (default=\"\")\n"
" This option specifies a proxy to S3 server.\n"
" Specify the proxy with '[<scheme://]hostname(fqdn)[:<port>]' formatted.\n"
" '<schema>://' can be omitted, and 'http://' is used when omitted.\n"
" Also, ':<port>' can also be omitted. If omitted, port 443 is used for\n"
" HTTPS schema, and port 1080 is used otherwise.\n"
" This option is the same as the curl command's '--proxy(-x)' option and\n"
" libcurl's 'CURLOPT_PROXY' flag.\n"
" This option is equivalent to and takes precedence over the environment\n"
" variables 'http_proxy', 'all_proxy', etc.\n"
"\n"
" proxy_cred_file (default=\"\")\n"
" This option specifies the file that describes the username and\n"
" passphrase for authentication of the proxy when the HTTP schema\n"
" proxy is specified by the 'proxy' option.\n"
" Username and passphrase are valid only for HTTP schema. If the HTTP\n"
" proxy does not require authentication, this option is not required.\n"
" Separate the username and passphrase with a ':' character and\n"
" specify each as a URL-encoded string.\n"
"\n"
" ipresolve (default=\"whatever\")\n"
" Select what type of IP addresses to use when establishing a\n"
" connection.\n"
" Default('whatever') can use addresses of all IP versions(IPv4 and\n"
" IPv6) that your system allows. If you specify 'IPv4', only IPv4\n"
" addresses are used. And when 'IPv6'is specified, only IPv6 addresses\n"
" will be used.\n"
"\n"
" logfile - specify the log output file.\n"
" s3fs outputs the log file to syslog. Alternatively, if s3fs is\n"
" started with the \"-f\" option specified, the log will be output\n"
" to the stdout/stderr.\n"
" You can use this option to specify the log file that s3fs outputs.\n"
" If you specify a log file with this option, it will reopen the log\n"
" file when s3fs receives a SIGHUP signal. You can use the SIGHUP\n"
" signal for log rotation.\n"
"\n"
" dbglevel (default=\"crit\")\n"
" Set the debug message level. set value as crit (critical), err\n"
" (error), warn (warning), info (information) to debug level.\n"
" default debug level is critical. If s3fs run with \"-d\" option,\n"
" the debug level is set information. When s3fs catch the signal\n"
" SIGUSR2, the debug level is bump up.\n"
"\n"
" curldbg - put curl debug message\n"
" Put the debug message from libcurl when this option is specified.\n"
" Specify \"normal\" or \"body\" for the parameter.\n"
" If the parameter is omitted, it is the same as \"normal\".\n"
" If \"body\" is specified, some API communication body data will be\n"
" output in addition to the debug message output as \"normal\".\n"
"\n"
" no_time_stamp_msg - no time stamp in debug message\n"
" The time stamp is output to the debug message by default.\n"
" If this option is specified, the time stamp will not be output\n"
" in the debug message.\n"
" It is the same even if the environment variable \"S3FS_MSGTIMESTAMP\"\n"
" is set to \"no\".\n"
"\n"
" set_check_cache_sigusr1 (default is stdout)\n"
" If the cache is enabled, you can check the integrity of the\n"
" cache file and the cache file's stats info file.\n"
" This option is specified and when sending the SIGUSR1 signal\n"
" to the s3fs process checks the cache status at that time.\n"
" This option can take a file path as parameter to output the\n"
" check result to that file. The file path parameter can be omitted.\n"
" If omitted, the result will be output to stdout or syslog.\n"
"\n"
" update_parent_dir_stat (default is disable)\n"
" The parent directory's mtime and ctime are updated when a file or\n"
" directory is created or deleted (when the parent directory's inode is\n"
" updated).\n"
" By default, parent directory statistics are not updated.\n"
"\n"
"FUSE/mount Options:\n"
"\n"
" Most of the generic mount options described in 'man mount' are\n"
" supported (ro, rw, suid, nosuid, dev, nodev, exec, noexec, atime,\n"
" noatime, sync async, dirsync). Filesystems are mounted with\n"
" '-onodev,nosuid' by default, which can only be overridden by a\n"
" privileged user.\n"
" \n"
" There are many FUSE specific mount options that can be specified.\n"
" e.g. allow_other See the FUSE's README for the full set.\n"
"\n"
"Utility mode Options:\n"
"\n"
" -u, --incomplete-mpu-list\n"
" Lists multipart incomplete objects uploaded to the specified\n"
" bucket.\n"
" --incomplete-mpu-abort (=all or =<date format>)\n"
" Delete the multipart incomplete object uploaded to the specified\n"
" bucket.\n"
" If \"all\" is specified for this option, all multipart incomplete\n"
" objects will be deleted. If you specify no argument as an option,\n"
" objects older than 24 hours (24H) will be deleted (This is the\n"
" default value). You can specify an optional date format. It can\n"
" be specified as year, month, day, hour, minute, second, and it is\n"
" expressed as \"Y\", \"M\", \"D\", \"h\", \"m\", \"s\" respectively.\n"
" For example, \"1Y6M10D12h30m30s\".\n"
"\n"
"Miscellaneous Options:\n"
"\n"
" -h, --help Output this help.\n"
" --version Output version info.\n"
" -d --debug Turn on DEBUG messages to syslog. Specifying -d\n"
" twice turns on FUSE debug messages to STDOUT.\n"
" -f FUSE foreground option - do not run as daemon.\n"
" -s FUSE single-threaded option\n"
" disable multi-threaded operation\n"
"\n"
"\n"
"s3fs home page: <https://github.com/s3fs-fuse/s3fs-fuse>\n"
;
//-------------------------------------------------------------------
// Functions
//-------------------------------------------------------------------
void show_usage()
{
printf("Usage: %s BUCKET:[PATH] MOUNTPOINT [OPTION]...\n", program_name.c_str());
}
void show_help()
{
show_usage();
printf(help_string);
}
void show_version()
{
printf(
"Amazon Simple Storage Service File System V%s%s with %s\n"
"Copyright (C) 2010 Randy Rizun <rrizun@gmail.com>\n"
"License GPL2: GNU GPL version 2 <https://gnu.org/licenses/gpl.html>\n"
"This is free software: you are free to change and redistribute it.\n"
"There is NO WARRANTY, to the extent permitted by law.\n",
VERSION, COMMIT_HASH_VAL, s3fs_crypt_lib_name());
}
const char* short_version()
{
static constexpr char short_ver[] = "s3fs version " VERSION "" COMMIT_HASH_VAL;
return short_ver;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

41
src/s3fs_help.h Normal file
View File

@ -0,0 +1,41 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_S3FS_HELP_H_
#define S3FS_S3FS_HELP_H_
//-------------------------------------------------------------------
// Functions
//-------------------------------------------------------------------
void show_usage();
void show_help();
void show_version();
const char* short_version();
#endif // S3FS_S3FS_HELP_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

307
src/s3fs_logger.cpp Normal file
View File

@ -0,0 +1,307 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#include <cstdlib>
#include <iomanip>
#include <memory>
#include <sstream>
#include <string>
#include <strings.h>
#include "common.h"
#include "s3fs_logger.h"
//-------------------------------------------------------------------
// S3fsLog class : variables
//-------------------------------------------------------------------
constexpr char S3fsLog::LOGFILEENV[];
constexpr const char* S3fsLog::nest_spaces[];
constexpr char S3fsLog::MSGTIMESTAMP[];
S3fsLog* S3fsLog::pSingleton = nullptr;
S3fsLog::Level S3fsLog::debug_level = S3fsLog::Level::CRIT;
FILE* S3fsLog::logfp = nullptr;
std::string S3fsLog::logfile;
bool S3fsLog::time_stamp = true;
//-------------------------------------------------------------------
// S3fsLog class : class methods
//-------------------------------------------------------------------
bool S3fsLog::IsS3fsLogLevel(S3fsLog::Level level)
{
return static_cast<int>(level) == (static_cast<int>(S3fsLog::debug_level) & static_cast<int>(level));
}
std::string S3fsLog::GetCurrentTime()
{
std::ostringstream current_time;
if(time_stamp){
struct timeval now;
struct timespec tsnow;
struct tm res;
char tmp[32];
if(-1 == clock_gettime(S3FS_CLOCK_MONOTONIC, &tsnow)){
now.tv_sec = tsnow.tv_sec;
now.tv_usec = (tsnow.tv_nsec / 1000);
}else{
gettimeofday(&now, nullptr);
}
strftime(tmp, sizeof(tmp), "%Y-%m-%dT%H:%M:%S", gmtime_r(&now.tv_sec, &res));
current_time << tmp << "." << std::setfill('0') << std::setw(3) << (now.tv_usec / 1000) << "Z ";
}
return current_time.str();
}
bool S3fsLog::SetLogfile(const char* pfile)
{
if(!S3fsLog::pSingleton){
S3FS_PRN_CRIT("S3fsLog::pSingleton is nullptr.");
return false;
}
return S3fsLog::pSingleton->LowSetLogfile(pfile);
}
bool S3fsLog::ReopenLogfile()
{
if(!S3fsLog::pSingleton){
S3FS_PRN_CRIT("S3fsLog::pSingleton is nullptr.");
return false;
}
if(!S3fsLog::logfp){
S3FS_PRN_INFO("Currently the log file is output to stdout/stderr.");
return true;
}
if(!S3fsLog::logfile.empty()){
S3FS_PRN_ERR("There is a problem with the path to the log file being empty.");
return false;
}
std::string tmp = S3fsLog::logfile;
return S3fsLog::pSingleton->LowSetLogfile(tmp.c_str());
}
S3fsLog::Level S3fsLog::SetLogLevel(S3fsLog::Level level)
{
if(!S3fsLog::pSingleton){
S3FS_PRN_CRIT("S3fsLog::pSingleton is nullptr.");
return S3fsLog::debug_level; // Although it is an error, it returns the current value.
}
return S3fsLog::pSingleton->LowSetLogLevel(level);
}
S3fsLog::Level S3fsLog::BumpupLogLevel()
{
if(!S3fsLog::pSingleton){
S3FS_PRN_CRIT("S3fsLog::pSingleton is nullptr.");
return S3fsLog::debug_level; // Although it is an error, it returns the current value.
}
return S3fsLog::pSingleton->LowBumpupLogLevel();
}
bool S3fsLog::SetTimeStamp(bool value)
{
bool old = S3fsLog::time_stamp;
S3fsLog::time_stamp = value;
return old;
}
//-------------------------------------------------------------------
// S3fsLog class : methods
//-------------------------------------------------------------------
S3fsLog::S3fsLog()
{
if(!S3fsLog::pSingleton){
S3fsLog::pSingleton = this;
// init syslog(default CRIT)
openlog("s3fs", LOG_PID | LOG_ODELAY | LOG_NOWAIT, LOG_USER);
LowLoadEnv();
}else{
S3FS_PRN_ERR("Already set singleton object for S3fsLog.");
}
}
S3fsLog::~S3fsLog()
{
if(S3fsLog::pSingleton == this){
FILE* oldfp = S3fsLog::logfp;
S3fsLog::logfp = nullptr;
if(oldfp && 0 != fclose(oldfp)){
S3FS_PRN_ERR("Could not close old log file(%s), but continue...", (S3fsLog::logfile.empty() ? S3fsLog::logfile.c_str() : "null"));
}
S3fsLog::logfile.clear();
S3fsLog::pSingleton = nullptr;
S3fsLog::debug_level = Level::CRIT;
closelog();
}else{
S3FS_PRN_ERR("This object is not singleton S3fsLog object.");
}
}
bool S3fsLog::LowLoadEnv()
{
if(S3fsLog::pSingleton != this){
S3FS_PRN_ERR("This object is not as same as S3fsLog::pSingleton.");
return false;
}
char* pEnvVal;
if(nullptr != (pEnvVal = getenv(S3fsLog::LOGFILEENV))){
if(!SetLogfile(pEnvVal)){
return false;
}
}
if(nullptr != (pEnvVal = getenv(S3fsLog::MSGTIMESTAMP))){
if(0 == strcasecmp(pEnvVal, "true") || 0 == strcasecmp(pEnvVal, "yes") || 0 == strcasecmp(pEnvVal, "1")){
S3fsLog::time_stamp = true;
}else if(0 == strcasecmp(pEnvVal, "false") || 0 == strcasecmp(pEnvVal, "no") || 0 == strcasecmp(pEnvVal, "0")){
S3fsLog::time_stamp = false;
}else{
S3FS_PRN_WARN("Unknown %s environment value(%s) is specified, skip to set time stamp mode.", S3fsLog::MSGTIMESTAMP, pEnvVal);
}
}
return true;
}
bool S3fsLog::LowSetLogfile(const char* pfile)
{
if(S3fsLog::pSingleton != this){
S3FS_PRN_ERR("This object is not as same as S3fsLog::pSingleton.");
return false;
}
if(!pfile){
// close log file if it is opened
if(S3fsLog::logfp && 0 != fclose(S3fsLog::logfp)){
S3FS_PRN_ERR("Could not close log file(%s).", (S3fsLog::logfile.empty() ? S3fsLog::logfile.c_str() : "null"));
return false;
}
S3fsLog::logfp = nullptr;
S3fsLog::logfile.clear();
}else{
// open new log file
//
// [NOTE]
// It will reopen even if it is the same file.
//
FILE* newfp;
if(nullptr == (newfp = fopen(pfile, "a+"))){
S3FS_PRN_ERR("Could not open log file(%s).", pfile);
return false;
}
// switch new log file and close old log file if it is opened
FILE* oldfp = S3fsLog::logfp;
if(oldfp && 0 != fclose(oldfp)){
S3FS_PRN_ERR("Could not close old log file(%s).", (!S3fsLog::logfile.empty() ? S3fsLog::logfile.c_str() : "null"));
fclose(newfp);
return false;
}
S3fsLog::logfp = newfp;
S3fsLog::logfile = pfile;
}
return true;
}
S3fsLog::Level S3fsLog::LowSetLogLevel(Level level)
{
if(S3fsLog::pSingleton != this){
S3FS_PRN_ERR("This object is not as same as S3fsLog::pSingleton.");
return S3fsLog::debug_level; // Although it is an error, it returns the current value.
}
if(level == S3fsLog::debug_level){
return S3fsLog::debug_level;
}
Level old = S3fsLog::debug_level;
S3fsLog::debug_level = level;
setlogmask(LOG_UPTO(GetSyslogLevel(S3fsLog::debug_level)));
S3FS_PRN_CRIT("change debug level from %sto %s", GetLevelString(old), GetLevelString(S3fsLog::debug_level));
return old;
}
S3fsLog::Level S3fsLog::LowBumpupLogLevel() const
{
if(S3fsLog::pSingleton != this){
S3FS_PRN_ERR("This object is not as same as S3fsLog::pSingleton.");
return S3fsLog::debug_level; // Although it is an error, it returns the current value.
}
Level old = S3fsLog::debug_level;
S3fsLog::debug_level = ( Level::CRIT == S3fsLog::debug_level ? Level::ERR :
Level::ERR == S3fsLog::debug_level ? Level::WARN :
Level::WARN == S3fsLog::debug_level ? Level::INFO :
Level::INFO == S3fsLog::debug_level ? Level::DBG : Level::CRIT );
setlogmask(LOG_UPTO(GetSyslogLevel(S3fsLog::debug_level)));
S3FS_PRN_CRIT("change debug level from %sto %s", GetLevelString(old), GetLevelString(S3fsLog::debug_level));
return old;
}
void s3fs_low_logprn(S3fsLog::Level level, const char* file, const char *func, int line, const char *fmt, ...)
{
if(S3fsLog::IsS3fsLogLevel(level)){
va_list va;
va_start(va, fmt);
size_t len = vsnprintf(nullptr, 0, fmt, va) + 1;
va_end(va);
auto message = std::make_unique<char[]>(len);
va_start(va, fmt);
vsnprintf(message.get(), len, fmt, va);
va_end(va);
if(foreground || S3fsLog::IsSetLogFile()){
S3fsLog::SeekEnd();
fprintf(S3fsLog::GetOutputLogFile(), "%s%s%s:%s(%d): %s\n", S3fsLog::GetCurrentTime().c_str(), S3fsLog::GetLevelString(level), file, func, line, message.get());
S3fsLog::Flush();
}else{
// TODO: why does this differ from s3fs_low_logprn2?
syslog(S3fsLog::GetSyslogLevel(level), "%s%s:%s(%d): %s", instance_name.c_str(), file, func, line, message.get());
}
}
}
void s3fs_low_logprn2(S3fsLog::Level level, int nest, const char* file, const char *func, int line, const char *fmt, ...)
{
if(S3fsLog::IsS3fsLogLevel(level)){
va_list va;
va_start(va, fmt);
size_t len = vsnprintf(nullptr, 0, fmt, va) + 1;
va_end(va);
auto message = std::make_unique<char[]>(len);
va_start(va, fmt);
vsnprintf(message.get(), len, fmt, va);
va_end(va);
if(foreground || S3fsLog::IsSetLogFile()){
S3fsLog::SeekEnd();
fprintf(S3fsLog::GetOutputLogFile(), "%s%s%s%s:%s(%d): %s\n", S3fsLog::GetCurrentTime().c_str(), S3fsLog::GetLevelString(level), S3fsLog::GetS3fsLogNest(nest), file, func, line, message.get());
S3fsLog::Flush();
}else{
syslog(S3fsLog::GetSyslogLevel(level), "%s%s%s", instance_name.c_str(), S3fsLog::GetS3fsLogNest(nest), message.get());
}
}
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

273
src/s3fs_logger.h Normal file
View File

@ -0,0 +1,273 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_LOGGER_H_
#define S3FS_LOGGER_H_
#include <cstdarg>
#include <cstdint>
#include <cstdio>
#include <string>
#include <syslog.h>
#include <sys/time.h>
#include "common.h"
#ifdef CLOCK_MONOTONIC_COARSE
#define S3FS_CLOCK_MONOTONIC CLOCK_MONOTONIC_COARSE
#else
// case of OSX
#define S3FS_CLOCK_MONOTONIC CLOCK_MONOTONIC
#endif
//-------------------------------------------------------------------
// S3fsLog class
//-------------------------------------------------------------------
class S3fsLog
{
public:
enum class Level : uint8_t {
CRIT = 0, // LEVEL_CRIT
ERR = 1, // LEVEL_ERR
WARN = 3, // LEVEL_WARNING
INFO = 7, // LEVEL_INFO
DBG = 15 // LEVEL_DEBUG
};
protected:
static constexpr int NEST_MAX = 4;
static constexpr const char* nest_spaces[NEST_MAX] = {"", " ", " ", " "};
static constexpr char LOGFILEENV[] = "S3FS_LOGFILE";
static constexpr char MSGTIMESTAMP[] = "S3FS_MSGTIMESTAMP";
static S3fsLog* pSingleton;
static Level debug_level;
static FILE* logfp;
static std::string logfile;
static bool time_stamp;
protected:
bool LowLoadEnv();
bool LowSetLogfile(const char* pfile);
Level LowSetLogLevel(Level level);
Level LowBumpupLogLevel() const;
public:
static bool IsS3fsLogLevel(Level level);
static bool IsS3fsLogCrit() { return IsS3fsLogLevel(Level::CRIT); }
static bool IsS3fsLogErr() { return IsS3fsLogLevel(Level::ERR); }
static bool IsS3fsLogWarn() { return IsS3fsLogLevel(Level::WARN); }
static bool IsS3fsLogInfo() { return IsS3fsLogLevel(Level::INFO); }
static bool IsS3fsLogDbg() { return IsS3fsLogLevel(Level::DBG); }
static constexpr int GetSyslogLevel(Level level)
{
int masked = static_cast<int>(level) & static_cast<int>(Level::DBG);
return ( static_cast<int>(Level::DBG) == masked ? LOG_DEBUG :
static_cast<int>(Level::INFO) == masked ? LOG_INFO :
static_cast<int>(Level::WARN) == masked ? LOG_WARNING :
static_cast<int>(Level::ERR) == masked ? LOG_ERR : LOG_CRIT );
}
static std::string GetCurrentTime();
static constexpr const char* GetLevelString(Level level)
{
int masked = static_cast<int>(level) & static_cast<int>(Level::DBG);
return ( static_cast<int>(Level::DBG) == masked ? "[DBG] " :
static_cast<int>(Level::INFO) == masked ? "[INF] " :
static_cast<int>(Level::WARN) == masked ? "[WAN] " :
static_cast<int>(Level::ERR) == masked ? "[ERR] " : "[CRT] " );
}
static constexpr const char* GetS3fsLogNest(int nest)
{
return nest_spaces[nest < NEST_MAX ? nest : NEST_MAX - 1];
}
static bool IsSetLogFile()
{
return (nullptr != logfp);
}
static FILE* GetOutputLogFile()
{
return (logfp ? logfp : stdout);
}
static FILE* GetErrorLogFile()
{
return (logfp ? logfp : stderr);
}
static void SeekEnd()
{
if(logfp){
fseek(logfp, 0, SEEK_END);
}
}
static void Flush()
{
if(logfp){
fflush(logfp);
}
}
static bool SetLogfile(const char* pfile);
static bool ReopenLogfile();
static Level SetLogLevel(Level level);
static Level BumpupLogLevel();
static bool SetTimeStamp(bool value);
explicit S3fsLog();
~S3fsLog();
S3fsLog(const S3fsLog&) = delete;
S3fsLog(S3fsLog&&) = delete;
S3fsLog& operator=(const S3fsLog&) = delete;
S3fsLog& operator=(S3fsLog&&) = delete;
};
//-------------------------------------------------------------------
// Debug macros
//-------------------------------------------------------------------
void s3fs_low_logprn(S3fsLog::Level level, const char* file, const char *func, int line, const char *fmt, ...) __attribute__ ((format (printf, 5, 6)));
#define S3FS_LOW_LOGPRN(level, fmt, ...) \
do{ \
s3fs_low_logprn(level, __FILE__, __func__, __LINE__, fmt, ##__VA_ARGS__); \
}while(0)
void s3fs_low_logprn2(S3fsLog::Level level, int nest, const char* file, const char *func, int line, const char *fmt, ...) __attribute__ ((format (printf, 6, 7)));
#define S3FS_LOW_LOGPRN2(level, nest, fmt, ...) \
do{ \
s3fs_low_logprn2(level, nest, __FILE__, __func__, __LINE__, fmt, ##__VA_ARGS__); \
}while(0)
#define S3FS_LOW_CURLDBG(fmt, ...) \
do{ \
if(foreground || S3fsLog::IsSetLogFile()){ \
S3fsLog::SeekEnd(); \
fprintf(S3fsLog::GetOutputLogFile(), "%s[CURL DBG] " fmt "%s\n", S3fsLog::GetCurrentTime().c_str(), __VA_ARGS__); \
S3fsLog::Flush(); \
}else{ \
syslog(S3fsLog::GetSyslogLevel(S3fsLog::Level::CRIT), "%s" fmt "%s", instance_name.c_str(), __VA_ARGS__); \
} \
}while(0)
#define S3FS_LOW_LOGPRN_EXIT(fmt, ...) \
do{ \
if(foreground || S3fsLog::IsSetLogFile()){ \
S3fsLog::SeekEnd(); \
fprintf(S3fsLog::GetErrorLogFile(), "s3fs: " fmt "%s\n", __VA_ARGS__); \
S3fsLog::Flush(); \
}else{ \
fprintf(S3fsLog::GetErrorLogFile(), "s3fs: " fmt "%s\n", __VA_ARGS__); \
syslog(S3fsLog::GetSyslogLevel(S3fsLog::Level::CRIT), "%ss3fs: " fmt "%s", instance_name.c_str(), __VA_ARGS__); \
} \
}while(0)
// Special macro for init message
#define S3FS_PRN_INIT_INFO(fmt, ...) \
do{ \
if(foreground || S3fsLog::IsSetLogFile()){ \
S3fsLog::SeekEnd(); \
fprintf(S3fsLog::GetOutputLogFile(), "%s%s%s%s:%s(%d): " fmt "%s\n", S3fsLog::GetCurrentTime().c_str(), S3fsLog::GetLevelString(S3fsLog::Level::INFO), S3fsLog::GetS3fsLogNest(0), __FILE__, __func__, __LINE__, __VA_ARGS__, ""); \
S3fsLog::Flush(); \
}else{ \
syslog(S3fsLog::GetSyslogLevel(S3fsLog::Level::INFO), "%s%s" fmt "%s", instance_name.c_str(), S3fsLog::GetS3fsLogNest(0), __VA_ARGS__, ""); \
} \
}while(0)
#define S3FS_PRN_LAUNCH_INFO(fmt, ...) \
do{ \
if(foreground || S3fsLog::IsSetLogFile()){ \
S3fsLog::SeekEnd(); \
fprintf(S3fsLog::GetOutputLogFile(), "%s%s" fmt "%s\n", S3fsLog::GetCurrentTime().c_str(), S3fsLog::GetLevelString(S3fsLog::Level::INFO), __VA_ARGS__, ""); \
S3fsLog::Flush(); \
}else{ \
syslog(S3fsLog::GetSyslogLevel(S3fsLog::Level::INFO), "%s" fmt "%s", instance_name.c_str(), __VA_ARGS__, ""); \
} \
}while(0)
// Special macro for checking cache files
#define S3FS_LOW_CACHE(fp, fmt, ...) \
do{ \
if(foreground || S3fsLog::IsSetLogFile()){ \
S3fsLog::SeekEnd(); \
fprintf(fp, fmt "%s\n", __VA_ARGS__); \
S3fsLog::Flush(); \
}else{ \
syslog(S3fsLog::GetSyslogLevel(S3fsLog::Level::INFO), "%s: " fmt "%s", instance_name.c_str(), __VA_ARGS__); \
} \
}while(0)
// [NOTE]
// small trick for VA_ARGS
//
#define S3FS_PRN_EXIT(fmt, ...) S3FS_LOW_LOGPRN_EXIT(fmt, ##__VA_ARGS__, "")
#define S3FS_PRN_CRIT(fmt, ...) S3FS_LOW_LOGPRN(S3fsLog::Level::CRIT, fmt, ##__VA_ARGS__)
#define S3FS_PRN_ERR(fmt, ...) S3FS_LOW_LOGPRN(S3fsLog::Level::ERR, fmt, ##__VA_ARGS__)
#define S3FS_PRN_WARN(fmt, ...) S3FS_LOW_LOGPRN(S3fsLog::Level::WARN, fmt, ##__VA_ARGS__)
#define S3FS_PRN_DBG(fmt, ...) S3FS_LOW_LOGPRN(S3fsLog::Level::DBG, fmt, ##__VA_ARGS__)
#define S3FS_PRN_INFO(fmt, ...) S3FS_LOW_LOGPRN2(S3fsLog::Level::INFO, 0, fmt, ##__VA_ARGS__)
#define S3FS_PRN_INFO1(fmt, ...) S3FS_LOW_LOGPRN2(S3fsLog::Level::INFO, 1, fmt, ##__VA_ARGS__)
#define S3FS_PRN_INFO2(fmt, ...) S3FS_LOW_LOGPRN2(S3fsLog::Level::INFO, 2, fmt, ##__VA_ARGS__)
#define S3FS_PRN_INFO3(fmt, ...) S3FS_LOW_LOGPRN2(S3fsLog::Level::INFO, 3, fmt, ##__VA_ARGS__)
#define S3FS_PRN_CURL(fmt, ...) S3FS_LOW_CURLDBG(fmt, ##__VA_ARGS__, "")
#define S3FS_PRN_CACHE(fp, ...) S3FS_LOW_CACHE(fp, ##__VA_ARGS__, "")
// Macros to print log with fuse context
#define PRINT_FUSE_CTX(level, indent, fmt, ...) do { \
if(S3fsLog::IsS3fsLogLevel(level)){ \
struct fuse_context *ctx = fuse_get_context(); \
if(ctx == NULL){ \
S3FS_LOW_LOGPRN2(level, indent, fmt, ##__VA_ARGS__); \
}else{ \
S3FS_LOW_LOGPRN2(level, indent, fmt"[pid=%u,uid=%u,gid=%u]",\
##__VA_ARGS__, \
(unsigned int)(ctx->pid), \
(unsigned int)(ctx->uid), \
(unsigned int)(ctx->gid)); \
} \
} \
} while (0)
#define FUSE_CTX_INFO(fmt, ...) do { \
PRINT_FUSE_CTX(S3fsLog::Level::INFO, 0, fmt, ##__VA_ARGS__); \
} while (0)
#define FUSE_CTX_INFO1(fmt, ...) do { \
PRINT_FUSE_CTX(S3fsLog::Level::INFO, 1, fmt, ##__VA_ARGS__); \
} while (0)
#define FUSE_CTX_DBG(fmt, ...) do { \
PRINT_FUSE_CTX(S3fsLog::Level::DBG, 0, fmt, ##__VA_ARGS__); \
} while (0)
#endif // S3FS_LOGGER_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

1517
src/s3fs_threadreqs.cpp Normal file

File diff suppressed because it is too large Load Diff

267
src/s3fs_threadreqs.h Normal file
View File

@ -0,0 +1,267 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_THREADREQS_H_
#define S3FS_THREADREQS_H_
#include <string>
#include "common.h"
#include "metaheader.h"
#include "curl.h"
#include "s3objlist.h"
#include "syncfiller.h"
#include "psemaphore.h"
//-------------------------------------------------------------------
// Structures for MultiThread Request
//-------------------------------------------------------------------
typedef std::map<std::string, int> retrycnt_t;
//
// Head Request parameter structure for Thread Pool.
//
struct head_req_thparam
{
std::string path;
headers_t* pmeta = nullptr;
int result = 0;
};
//
// Multi Head Request parameter structure for Thread Pool.
//
struct multi_head_req_thparam
{
std::string path;
SyncFiller* psyncfiller = nullptr;
std::mutex* pthparam_lock = nullptr;
int* pretrycount = nullptr;
s3obj_list_t* pnotfound_list = nullptr;
bool use_wtf8 = false;
objtype_t objtype = objtype_t::UNKNOWN;
int* presult = nullptr;
};
//
// Delete Request parameter structure for Thread Pool.
//
struct delete_req_thparam
{
std::string path;
int result = 0;
};
//
// Put Head Request parameter structure for Thread Pool.
//
struct put_head_req_thparam
{
std::string path;
headers_t meta;
bool isCopy = false;
int result = 0;
};
//
// Put Request parameter structure for Thread Pool.
//
struct put_req_thparam
{
std::string path;
headers_t meta;
int fd = -1;
bool ahbe = false;
int result = 0;
};
//
// List Bucket Request parameter structure for Thread Pool.
//
struct list_bucket_req_thparam
{
std::string path;
std::string query;
std::string* presponseBody = nullptr;
int result = 0;
};
//
// Check Service Request parameter structure for Thread Pool.
//
struct check_service_req_thparam
{
std::string path;
bool forceNoSSE = false;
bool support_compat_dir = false;
long* presponseCode = nullptr;
std::string* presponseBody = nullptr;
int result = 0;
};
//
// Pre Multipart Upload Request parameter structure for Thread Pool.
//
struct pre_multipart_upload_req_thparam
{
std::string path;
headers_t meta;
std::string upload_id;
int result = 0;
};
//
// Multipart Upload Part Request parameter structure for Thread Pool.
//
struct multipart_upload_part_req_thparam
{
std::string path;
std::string upload_id;
int upload_fd = -1;
off_t start = 0;
off_t size = 0;
bool is_copy = false;
int part_num = -1;
std::mutex* pthparam_lock = nullptr;
etagpair* petag = nullptr;
int* presult = nullptr;
};
//
// Complete Multipart Upload Request parameter structure for Thread Pool.
//
struct complete_multipart_upload_req_thparam
{
std::string path;
std::string upload_id;
etaglist_t etaglist;
int result = 0;
};
//
// Abort Multipart Upload Request parameter structure for Thread Pool.
//
struct abort_multipart_upload_req_thparam
{
std::string path;
std::string upload_id;
int result = 0;
};
//
// Multipart Put Head Request parameter structure for Thread Pool.
//
struct multipart_put_head_req_thparam
{
std::string from;
std::string to;
std::string upload_id;
int part_number = 0;
headers_t meta;
std::mutex* pthparam_lock = nullptr;
filepart* ppartdata = nullptr;
int* pretrycount = nullptr;
int* presult = nullptr;
};
//
// Parallel Get Object Request parameter structure for Thread Pool.
//
struct parallel_get_object_req_thparam
{
std::string path;
int fd = -1;
off_t start = 0;
off_t size = 0;
sse_type_t ssetype = sse_type_t::SSE_DISABLE;
std::string ssevalue;
std::mutex* pthparam_lock = nullptr;
int* pretrycount = nullptr;
int* presult = nullptr;
};
//
// Get Object Request parameter structure for Thread Pool.
//
struct get_object_req_thparam
{
std::string path;
int fd = -1;
off_t start = 0;
off_t size = 0;
int result = 0;
};
//-------------------------------------------------------------------
// Thread Worker functions for MultiThread Request
//-------------------------------------------------------------------
void* head_req_threadworker(S3fsCurl& s3fscurl, void* arg);
void* multi_head_req_threadworker(S3fsCurl& s3fscurl, void* arg);
void* delete_req_threadworker(S3fsCurl& s3fscurl, void* arg);
void* put_head_req_threadworker(S3fsCurl& s3fscurl, void* arg);
void* put_req_threadworker(S3fsCurl& s3fscurl, void* arg);
void* list_bucket_req_threadworker(S3fsCurl& s3fscurl, void* arg);
void* check_service_req_threadworker(S3fsCurl& s3fscurl, void* arg);
void* pre_multipart_upload_req_threadworker(S3fsCurl& s3fscurl, void* arg);
void* multipart_upload_part_req_threadworker(S3fsCurl& s3fscurl, void* arg);
void* complete_multipart_upload_threadworker(S3fsCurl& s3fscurl, void* arg);
void* abort_multipart_upload_req_threadworker(S3fsCurl& s3fscurl, void* arg);
void* multipart_put_head_req_threadworker(S3fsCurl& s3fscurl, void* arg);
void* parallel_get_object_req_threadworker(S3fsCurl& s3fscurl, void* arg);
void* get_object_req_threadworker(S3fsCurl& s3fscurl, void* arg);
//-------------------------------------------------------------------
// Utility functions
//-------------------------------------------------------------------
int head_request(const std::string& strpath, headers_t& header);
int multi_head_request(const std::string& strpath, SyncFiller& syncfiller, std::mutex& thparam_lock, int& retrycount, s3obj_list_t& notfound_list, bool use_wtf8, objtype_t objtype, int& result, Semaphore& sem);
int delete_request(const std::string& strpath);
int put_head_request(const std::string& strpath, const headers_t& meta, bool is_copy);
int put_request(const std::string& strpath, const headers_t& meta, int fd, bool ahbe);
int list_bucket_request(const std::string& strpath, const std::string& query, std::string& responseBody);
int check_service_request(const std::string& strpath, bool forceNoSSE, bool support_compat_dir, long& responseCode, std::string& responseBody);
int pre_multipart_upload_request(const std::string& path, const headers_t& meta, std::string& upload_id);
int multipart_upload_part_request(const std::string& path, int upload_fd, off_t start, off_t size, int part_num, const std::string& upload_id, etagpair* petag, bool is_copy, Semaphore* psem, std::mutex* pthparam_lock, int* req_result);
int await_multipart_upload_part_request(const std::string& path, int upload_fd, off_t start, off_t size, int part_num, const std::string& upload_id, etagpair* petag, bool is_copy);
int multipart_upload_request(const std::string& path, const headers_t& meta, int upload_fd);
int mix_multipart_upload_request(const std::string& path, headers_t& meta, int upload_fd, const fdpage_list_t& mixuppages);
int complete_multipart_upload_request(const std::string& path, const std::string& upload_id, const etaglist_t& parts);
int abort_multipart_upload_request(const std::string& path, const std::string& upload_id);
int multipart_put_head_request(const std::string& strfrom, const std::string& strto, off_t size, const headers_t& meta);
int parallel_get_object_request(const std::string& path, int fd, off_t start, off_t size);
int get_object_request(const std::string& path, int fd, off_t start, off_t size);
//-------------------------------------------------------------------
// Direct Call Utility Functions
//-------------------------------------------------------------------
int get_iamv2api_token_request(const std::string& strurl, int tokenttl, const std::string& strttlhdr, std::string& token);
int get_iamrole_request(const std::string& strurl, const std::string& striamtoken, std::string& token);
int get_iamcred_request(const std::string& strurl, const std::string& striamtoken, const std::string& stribmsecret, std::string& cred);
#endif // S3FS_THREADREQS_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright 2007-2008 Randy Rizun <rrizun@gmail.com>
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -17,120 +17,83 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef S3FS_S3FS_UTIL_H_
#define S3FS_S3FS_UTIL_H_
//-------------------------------------------------------------------
// Typedef
//-------------------------------------------------------------------
//
// Struct
//
struct s3obj_entry{
std::string normalname; // normalized name: if empty, object is nomalized name.
std::string orgname; // original name: if empty, object is original name.
std::string etag;
bool is_dir;
#include <cstdint>
#include <functional>
#include <string>
#include <sys/stat.h>
s3obj_entry() : is_dir(false) {}
};
typedef std::map<std::string, struct s3obj_entry> s3obj_t;
typedef std::list<std::string> s3obj_list_t;
//
// Class
//
class S3ObjList
{
private:
s3obj_t objects;
private:
bool insert_nomalized(const char* name, const char* normalized, bool is_dir);
const s3obj_entry* GetS3Obj(const char* name) const;
s3obj_t::const_iterator begin(void) const {
return objects.begin();
}
s3obj_t::const_iterator end(void) const {
return objects.end();
}
public:
S3ObjList() {}
~S3ObjList() {}
bool IsEmpty(void) const {
return objects.empty();
}
bool insert(const char* name, const char* etag = NULL, bool is_dir = false);
std::string GetOrgName(const char* name) const;
std::string GetNormalizedName(const char* name) const;
std::string GetETag(const char* name) const;
bool IsDir(const char* name) const;
bool GetNameList(s3obj_list_t& list, bool OnlyNormalized = true, bool CutSlash = true) const;
bool GetLastName(std::string& lastname) const;
static bool MakeHierarchizedList(s3obj_list_t& list, bool haveSlash);
};
typedef struct mvnode {
char *old_path;
char *new_path;
bool is_dir;
bool is_normdir;
struct mvnode *prev;
struct mvnode *next;
} MVNODE;
class AutoLock
{
private:
pthread_mutex_t* auto_mutex;
public:
explicit AutoLock(pthread_mutex_t* pmutex);
~AutoLock();
};
#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 0
#endif
#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC CLOCK_REALTIME
#endif
#ifndef CLOCK_MONOTONIC_COARSE
#define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC
#endif
//-------------------------------------------------------------------
// Functions
//-------------------------------------------------------------------
std::string get_realpath(const char *path);
MVNODE *create_mvnode(const char *old_path, const char *new_path, bool is_dir, bool normdir = false);
MVNODE *add_mvnode(MVNODE** head, MVNODE** tail, const char *old_path, const char *new_path, bool is_dir, bool normdir = false);
void free_mvnodes(MVNODE *head);
void init_sysconf_vars();
std::string get_username(uid_t uid);
int is_uid_inculde_group(uid_t uid, gid_t gid);
int is_uid_include_group(uid_t uid, gid_t gid);
std::string mydirname(const char* path);
std::string mydirname(const std::string& path);
std::string mybasename(const char* path);
std::string mybasename(const std::string& path);
std::string mydirname(std::string path);
std::string mybasename(std::string path);
int mkdirp(const std::string& path, mode_t mode);
std::string get_exist_directory_path(const std::string& path);
bool check_exist_dir_permission(const char* dirpath);
bool delete_files_in_dir(const char* dir, bool is_remove_own);
time_t get_mtime(const char *s);
time_t get_mtime(headers_t& meta, bool overcheck = true);
off_t get_size(const char *s);
off_t get_size(headers_t& meta);
mode_t get_mode(const char *s);
mode_t get_mode(headers_t& meta, const char* path = NULL, bool checkdir = false, bool forcedir = false);
uid_t get_uid(const char *s);
uid_t get_uid(headers_t& meta);
gid_t get_gid(const char *s);
gid_t get_gid(headers_t& meta);
blkcnt_t get_blocks(off_t size);
time_t cvtIAMExpireStringToTime(const char* s);
time_t get_lastmodified(const char* s);
time_t get_lastmodified(headers_t& meta);
bool is_need_check_obj_detail(headers_t& meta);
bool compare_sysname(const char* target);
void show_usage(void);
void show_help(void);
void show_version(void);
void print_launch_message(int argc, char** argv);
//-------------------------------------------------------------------
// Utility for nanosecond time(timespec)
//-------------------------------------------------------------------
// Wrap fclose since it is illegal to take the address of a stdlib function
int s3fs_fclose(FILE* fp);
class scope_guard
{
public:
template<class Callable>
explicit scope_guard(Callable&& undo_func)
: func(std::forward<Callable>(undo_func))
{}
~scope_guard()
{
if(func != nullptr) {
func();
}
}
void dismiss()
{
func = nullptr;
}
scope_guard(const scope_guard&) = delete;
scope_guard(scope_guard&& other) = delete;
scope_guard& operator=(const scope_guard&) = delete;
scope_guard& operator=(scope_guard&&) = delete;
private:
std::function<void()> func;
};
#endif // S3FS_S3FS_UTIL_H_
@ -139,6 +102,6 @@ void show_version(void);
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

512
src/s3fs_xml.cpp Normal file
View File

@ -0,0 +1,512 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Takeshi Nakatani <ggtakec.com>
*
* 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.
*/
#include <cstdio>
#include <cstdlib>
#include <libxml/xpathInternals.h>
#include <mutex>
#include <string>
#include "common.h"
#include "s3fs_logger.h"
#include "s3fs_xml.h"
#include "s3fs_util.h"
#include "s3objlist.h"
#include "string_util.h"
//-------------------------------------------------------------------
// Symbols
//-------------------------------------------------------------------
enum class get_object_name_result : std::uint8_t {
SUCCESS,
FAILURE,
FILE_OR_SUBDIR_IN_DIR
};
//-------------------------------------------------------------------
// Variables
//-------------------------------------------------------------------
// [NOTE]
// mutex for static variables in GetXmlNsUrl
//
static std::mutex xml_parser_mutex;
//-------------------------------------------------------------------
// Functions
//-------------------------------------------------------------------
static bool GetXmlNsUrl(xmlDocPtr doc, std::string& nsurl)
{
bool result = false;
if(!doc){
return result;
}
std::string tmpNs;
{
static time_t tmLast = 0; // cache for 60 sec.
static std::string strNs;
const std::lock_guard<std::mutex> lock(xml_parser_mutex);
if((tmLast + 60) < time(nullptr)){
// refresh
tmLast = time(nullptr);
strNs = "";
xmlNodePtr pRootNode = xmlDocGetRootElement(doc);
if(pRootNode){
std::unique_ptr<xmlNsPtr, decltype(xmlFree)> nslist(xmlGetNsList(doc, pRootNode), xmlFree);
if(nslist){
if(*nslist && (*nslist)[0].href){
int len = xmlStrlen((*nslist)[0].href);
if(0 < len){
strNs = std::string(reinterpret_cast<const char*>((*nslist)[0].href), len);
}
}
}
}
}
tmpNs = strNs;
}
if(!tmpNs.empty()){
nsurl = tmpNs;
result = true;
}
return result;
}
static unique_ptr_xmlChar get_base_exp(xmlDocPtr doc, const char* exp)
{
std::string xmlnsurl;
std::string exp_string;
if(!doc){
return {nullptr, xmlFree};
}
unique_ptr_xmlXPathContext ctx(xmlXPathNewContext(doc), xmlXPathFreeContext);
if(!noxmlns && GetXmlNsUrl(doc, xmlnsurl)){
xmlXPathRegisterNs(ctx.get(), reinterpret_cast<const xmlChar*>("s3"), reinterpret_cast<const xmlChar*>(xmlnsurl.c_str()));
exp_string = "/s3:ListBucketResult/s3:";
} else {
exp_string = "/ListBucketResult/";
}
exp_string += exp;
unique_ptr_xmlXPathObject marker_xp(xmlXPathEvalExpression(reinterpret_cast<const xmlChar*>(exp_string.c_str()), ctx.get()), xmlXPathFreeObject);
if(nullptr == marker_xp){
return {nullptr, xmlFree};
}
if(xmlXPathNodeSetIsEmpty(marker_xp->nodesetval)){
S3FS_PRN_INFO("marker_xp->nodesetval is empty.");
return {nullptr, xmlFree};
}
xmlNodeSetPtr nodes = marker_xp->nodesetval;
unique_ptr_xmlChar result(xmlNodeListGetString(doc, nodes->nodeTab[0]->xmlChildrenNode, 1), xmlFree);
return result;
}
static unique_ptr_xmlChar get_prefix(xmlDocPtr doc)
{
return get_base_exp(doc, "Prefix");
}
unique_ptr_xmlChar get_next_continuation_token(xmlDocPtr doc)
{
return get_base_exp(doc, "NextContinuationToken");
}
unique_ptr_xmlChar get_next_marker(xmlDocPtr doc)
{
return get_base_exp(doc, "NextMarker");
}
static std::pair<get_object_name_result, std::string> get_object_name(xmlDocPtr doc, xmlNodePtr node, const char* path)
{
// Get full path
unique_ptr_xmlChar fullpath(xmlNodeListGetString(doc, node, 1), xmlFree);
if(!fullpath){
S3FS_PRN_ERR("could not get object full path name..");
return {get_object_name_result::FAILURE, ""};
}
// basepath(path) is as same as fullpath.
if(0 == strcmp(reinterpret_cast<char*>(fullpath.get()), path)){
return {get_object_name_result::FILE_OR_SUBDIR_IN_DIR, ""};
}
// Make dir path and filename
std::string strdirpath = mydirname(reinterpret_cast<const char*>(fullpath.get()));
std::string strmybpath = mybasename(reinterpret_cast<const char*>(fullpath.get()));
const char* dirpath = strdirpath.c_str();
const char* mybname = strmybpath.c_str();
const char* basepath= (path && '/' == path[0]) ? &path[1] : path;
if('\0' == mybname[0]){
return {get_object_name_result::FAILURE, ""};
}
// check subdir & file in subdir
if(0 < strlen(dirpath)){
// case of "/"
if(0 == strcmp(mybname, "/") && 0 == strcmp(dirpath, "/")){
return {get_object_name_result::FILE_OR_SUBDIR_IN_DIR, ""};
}
// case of "."
if(0 == strcmp(mybname, ".") && 0 == strcmp(dirpath, ".")){
return {get_object_name_result::FILE_OR_SUBDIR_IN_DIR, ""};
}
// case of ".."
if(0 == strcmp(mybname, "..") && 0 == strcmp(dirpath, ".")){
return {get_object_name_result::FILE_OR_SUBDIR_IN_DIR, ""};
}
// case of "name"
if(0 == strcmp(dirpath, ".")){
// OK
return {get_object_name_result::SUCCESS, mybname};
}else{
if(basepath && 0 == strcmp(dirpath, basepath)){
// OK
return {get_object_name_result::SUCCESS, mybname};
}else if(basepath && 0 < strlen(basepath) && '/' == basepath[strlen(basepath) - 1] && 0 == strncmp(dirpath, basepath, strlen(basepath) - 1)){
std::string withdirname;
if(strlen(dirpath) > strlen(basepath)){
withdirname = &dirpath[strlen(basepath)];
}
// cppcheck-suppress unmatchedSuppression
// cppcheck-suppress knownConditionTrueFalse
if(!withdirname.empty() && '/' != *withdirname.rbegin()){
withdirname += "/";
}
withdirname += mybname;
return {get_object_name_result::SUCCESS, withdirname};
}
}
}
// case of something wrong
return {get_object_name_result::FILE_OR_SUBDIR_IN_DIR, ""};
}
static unique_ptr_xmlChar get_exp_value_xml(xmlDocPtr doc, xmlXPathContextPtr ctx, const char* exp_key)
{
if(!doc || !ctx || !exp_key){
return {nullptr, xmlFree};
}
xmlNodeSetPtr exp_nodes;
// search exp_key tag
unique_ptr_xmlXPathObject exp(xmlXPathEvalExpression(reinterpret_cast<const xmlChar*>(exp_key), ctx), xmlXPathFreeObject);
if(nullptr == exp){
S3FS_PRN_ERR("Could not find key(%s).", exp_key);
return {nullptr, xmlFree};
}
if(xmlXPathNodeSetIsEmpty(exp->nodesetval)){
S3FS_PRN_ERR("Key(%s) node is empty.", exp_key);
return {nullptr, xmlFree};
}
// get exp_key value & set in struct
exp_nodes = exp->nodesetval;
unique_ptr_xmlChar exp_value(xmlNodeListGetString(doc, exp_nodes->nodeTab[0]->xmlChildrenNode, 1), xmlFree);
if(nullptr == exp_value){
S3FS_PRN_ERR("Key(%s) value is empty.", exp_key);
return {nullptr, xmlFree};
}
return exp_value;
}
bool get_incomp_mpu_list(xmlDocPtr doc, incomp_mpu_list_t& list)
{
if(!doc){
return false;
}
unique_ptr_xmlXPathContext ctx(xmlXPathNewContext(doc), xmlXPathFreeContext);
std::string xmlnsurl;
std::string ex_upload = "//";
std::string ex_key;
std::string ex_id;
std::string ex_date;
if(!noxmlns && GetXmlNsUrl(doc, xmlnsurl)){
xmlXPathRegisterNs(ctx.get(), reinterpret_cast<const xmlChar*>("s3"), reinterpret_cast<const xmlChar*>(xmlnsurl.c_str()));
ex_upload += "s3:";
ex_key += "s3:";
ex_id += "s3:";
ex_date += "s3:";
}
ex_upload += "Upload";
ex_key += "Key";
ex_id += "UploadId";
ex_date += "Initiated";
// get "Upload" Tags
unique_ptr_xmlXPathObject upload_xp(xmlXPathEvalExpression(reinterpret_cast<const xmlChar*>(ex_upload.c_str()), ctx.get()), xmlXPathFreeObject);
if(nullptr == upload_xp){
S3FS_PRN_ERR("xmlXPathEvalExpression returns null.");
return false;
}
if(xmlXPathNodeSetIsEmpty(upload_xp->nodesetval)){
S3FS_PRN_INFO("upload_xp->nodesetval is empty.");
return true;
}
// Make list
int cnt;
xmlNodeSetPtr upload_nodes;
list.clear();
for(cnt = 0, upload_nodes = upload_xp->nodesetval; cnt < upload_nodes->nodeNr; cnt++){
ctx->node = upload_nodes->nodeTab[cnt];
INCOMP_MPU_INFO part;
// search "Key" tag
unique_ptr_xmlChar ex_value(get_exp_value_xml(doc, ctx.get(), ex_key.c_str()));
if(nullptr == ex_value){
continue;
}
if('/' != *(reinterpret_cast<char*>(ex_value.get()))){
part.key = "/";
}else{
part.key = "";
}
part.key += reinterpret_cast<char*>(ex_value.get());
// search "UploadId" tag
if(nullptr == (ex_value = get_exp_value_xml(doc, ctx.get(), ex_id.c_str()))){
continue;
}
part.id = reinterpret_cast<char*>(ex_value.get());
// search "Initiated" tag
if(nullptr == (ex_value = get_exp_value_xml(doc, ctx.get(), ex_date.c_str()))){
continue;
}
part.date = reinterpret_cast<char*>(ex_value.get());
list.push_back(part);
}
return true;
}
bool is_truncated(xmlDocPtr doc)
{
unique_ptr_xmlChar strTruncate(get_base_exp(doc, "IsTruncated"));
if(!strTruncate){
return false;
}
return 0 == strcasecmp(reinterpret_cast<const char*>(strTruncate.get()), "true");
}
int append_objects_from_xml_ex(const char* path, xmlDocPtr doc, xmlXPathContextPtr ctx, const char* ex_contents, const char* ex_key, const char* ex_etag, int isCPrefix, S3ObjList& head, bool prefix)
{
xmlNodeSetPtr content_nodes;
unique_ptr_xmlXPathObject contents_xp(xmlXPathEvalExpression(reinterpret_cast<const xmlChar*>(ex_contents), ctx), xmlXPathFreeObject);
if(nullptr == contents_xp){
S3FS_PRN_ERR("xmlXPathEvalExpression returns null.");
return -1;
}
if(xmlXPathNodeSetIsEmpty(contents_xp->nodesetval)){
S3FS_PRN_DBG("contents_xp->nodesetval is empty.");
return 0;
}
content_nodes = contents_xp->nodesetval;
bool is_dir;
std::string stretag;
int i;
for(i = 0; i < content_nodes->nodeNr; i++){
ctx->node = content_nodes->nodeTab[i];
// object name
unique_ptr_xmlXPathObject key(xmlXPathEvalExpression(reinterpret_cast<const xmlChar*>(ex_key), ctx), xmlXPathFreeObject);
if(nullptr == key){
S3FS_PRN_WARN("key is null. but continue.");
continue;
}
if(xmlXPathNodeSetIsEmpty(key->nodesetval)){
S3FS_PRN_WARN("node is empty. but continue.");
continue;
}
xmlNodeSetPtr key_nodes = key->nodesetval;
auto result = get_object_name(doc, key_nodes->nodeTab[0]->xmlChildrenNode, path);
switch(result.first){
case get_object_name_result::FAILURE:
S3FS_PRN_WARN("name is something wrong. but continue.");
break;
case get_object_name_result::SUCCESS: {
is_dir = isCPrefix ? true : false;
stretag = "";
if(!isCPrefix && ex_etag){
// Get ETag
unique_ptr_xmlXPathObject ETag(xmlXPathEvalExpression(reinterpret_cast<const xmlChar*>(ex_etag), ctx), xmlXPathFreeObject);
if(nullptr != ETag){
if(xmlXPathNodeSetIsEmpty(ETag->nodesetval)){
S3FS_PRN_INFO("ETag->nodesetval is empty.");
}else{
xmlNodeSetPtr etag_nodes = ETag->nodesetval;
unique_ptr_xmlChar petag(xmlNodeListGetString(doc, etag_nodes->nodeTab[0]->xmlChildrenNode, 1), xmlFree);
if(petag){
stretag = reinterpret_cast<const char*>(petag.get());
}
}
}
}
// [NOTE]
// The XML data passed to this function is CR code(\r) encoded.
// The function below decodes that encoded CR code.
//
std::string decname = get_decoded_cr_code(result.second.c_str());
if(prefix){
head.AddCommonPrefix(decname);
}
if(!head.insert(decname.c_str(), (!stretag.empty() ? stretag.c_str() : nullptr), is_dir)){
S3FS_PRN_ERR("insert_object returns with error.");
return -1;
}
break;
}
case get_object_name_result::FILE_OR_SUBDIR_IN_DIR:
S3FS_PRN_DBG("name is file or subdir in dir. but continue.");
break;
}
}
return 0;
}
int append_objects_from_xml(const char* path, xmlDocPtr doc, S3ObjList& head)
{
std::string xmlnsurl;
std::string ex_contents = "//";
std::string ex_key;
std::string ex_cprefix = "//";
std::string ex_prefix;
std::string ex_etag;
if(!doc){
return -1;
}
// If there is not <Prefix>, use path instead of it.
auto pprefix = get_prefix(doc);
std::string prefix = (pprefix ? reinterpret_cast<char*>(pprefix.get()) : path ? path : "");
unique_ptr_xmlXPathContext ctx(xmlXPathNewContext(doc), xmlXPathFreeContext);
if(!noxmlns && GetXmlNsUrl(doc, xmlnsurl)){
xmlXPathRegisterNs(ctx.get(), reinterpret_cast<const xmlChar*>("s3"), reinterpret_cast<const xmlChar*>(xmlnsurl.c_str()));
ex_contents+= "s3:";
ex_key += "s3:";
ex_cprefix += "s3:";
ex_prefix += "s3:";
ex_etag += "s3:";
}
ex_contents+= "Contents";
ex_key += "Key";
ex_cprefix += "CommonPrefixes";
ex_prefix += "Prefix";
ex_etag += "ETag";
if(-1 == append_objects_from_xml_ex(prefix.c_str(), doc, ctx.get(), ex_contents.c_str(), ex_key.c_str(), ex_etag.c_str(), 0, head, /*prefix=*/ false) ||
-1 == append_objects_from_xml_ex(prefix.c_str(), doc, ctx.get(), ex_cprefix.c_str(), ex_prefix.c_str(), nullptr, 1, head, /*prefix=*/ true) )
{
S3FS_PRN_ERR("append_objects_from_xml_ex returns with error.");
return -1;
}
return 0;
}
//-------------------------------------------------------------------
// Utility functions
//-------------------------------------------------------------------
bool simple_parse_xml(const char* data, size_t len, const char* key, std::string& value)
{
bool result = false;
if(!data || !key || 0 == len){
return false;
}
value.clear();
// [NOTE]
// If data is not nullptr and len is 0, this function will output the message
// ":1: parser error : Document is empty" to stderr.
// Make sure len is not 0 beforehand.
//
s3fsXmlBufferParserError parserError;
parserError.SetXmlParseError();
std::unique_ptr<xmlDoc, decltype(&xmlFreeDoc)> doc(xmlReadMemory(data, static_cast<int>(len), "", nullptr, 0), xmlFreeDoc);
if(nullptr == doc){
if(parserError.IsXmlParseError()){
S3FS_PRN_ERR("xmlReadMemory returns with error: %s", parserError.GetXmlParseError().c_str());
}else{
S3FS_PRN_ERR("xmlReadMemory returns with error.");
}
return false;
}
if(nullptr == doc->children){
return false;
}
for(xmlNodePtr cur_node = doc->children->children; nullptr != cur_node; cur_node = cur_node->next){
// For DEBUG
// std::string cur_node_name(reinterpret_cast<const char *>(cur_node->name));
// printf("cur_node_name: %s\n", cur_node_name.c_str());
if(XML_ELEMENT_NODE == cur_node->type){
std::string elementName = reinterpret_cast<const char*>(cur_node->name);
// For DEBUG
// printf("elementName: %s\n", elementName.c_str());
if(cur_node->children){
if(XML_TEXT_NODE == cur_node->children->type){
if(elementName == key) {
value = reinterpret_cast<const char *>(cur_node->children->content);
result = true;
break;
}
}
}
}
}
return result;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

99
src/s3fs_xml.h Normal file
View File

@ -0,0 +1,99 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_S3FS_XML_H_
#define S3FS_S3FS_XML_H_
#include <libxml/xpath.h>
#include <libxml/parser.h> // [NOTE] include this header in some environments
#include <memory>
#include <string>
#include <array>
#include <cstring>
#include "mpu_util.h"
class S3ObjList;
typedef std::unique_ptr<xmlChar, decltype(xmlFree)> unique_ptr_xmlChar;
typedef std::unique_ptr<xmlXPathObject, decltype(&xmlXPathFreeObject)> unique_ptr_xmlXPathObject;
typedef std::unique_ptr<xmlXPathContext, decltype(&xmlXPathFreeContext)> unique_ptr_xmlXPathContext;
typedef std::unique_ptr<xmlDoc, decltype(&xmlFreeDoc)> unique_ptr_xmlDoc;
//-------------------------------------------------------------------
// Utility Class
//-------------------------------------------------------------------
class s3fsXmlBufferParserError
{
private:
static constexpr int ERROR_BUFFER_SIZE = 1024;
std::array<char, ERROR_BUFFER_SIZE> error_buffer{};
static void ParserErrorHandler(void* ctx, const char *msg, ...)
{
auto* errbuf = static_cast<char*>(ctx);
if(errbuf){
va_list args;
va_start(args, msg);
vsnprintf(errbuf + strlen(errbuf), ERROR_BUFFER_SIZE - strlen(errbuf) - 1, msg, args);
va_end(args);
}
}
public:
void SetXmlParseError()
{
error_buffer.fill(0);
xmlSetGenericErrorFunc(error_buffer.data(), s3fsXmlBufferParserError::ParserErrorHandler);
}
std::string GetXmlParseError() const
{
return strlen(error_buffer.data()) ? error_buffer.data() : "";
}
bool IsXmlParseError() const
{
return (0 < strlen(error_buffer.data()));
}
};
//-------------------------------------------------------------------
// Functions
//-------------------------------------------------------------------
bool is_truncated(xmlDocPtr doc);
int append_objects_from_xml_ex(const char* path, xmlDocPtr doc, xmlXPathContextPtr ctx, const char* ex_contents, const char* ex_key, const char* ex_etag, int isCPrefix, S3ObjList& head, bool prefix);
int append_objects_from_xml(const char* path, xmlDocPtr doc, S3ObjList& head);
unique_ptr_xmlChar get_next_continuation_token(xmlDocPtr doc);
unique_ptr_xmlChar get_next_marker(xmlDocPtr doc);
bool get_incomp_mpu_list(xmlDocPtr doc, incomp_mpu_list_t& list);
bool simple_parse_xml(const char* data, size_t len, const char* key, std::string& value);
#endif // S3FS_S3FS_XML_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

305
src/s3objlist.cpp Normal file
View File

@ -0,0 +1,305 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Takeshi Nakatani <ggtakec.com>
*
* 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.
*/
#include <cstdio>
#include <cstring>
#include <string>
#include "s3objlist.h"
//-------------------------------------------------------------------
// Class S3ObjList
//-------------------------------------------------------------------
// New class S3ObjList is base on old s3_object struct.
// This class is for S3 compatible clients.
//
// If name is terminated by "/", it is forced dir type.
// If name is terminated by "_$folder$", it is forced dir type.
// If is_dir is true, the name ends with "/", or the name ends with "_$folder$",
// it will be determined to be a directory.
// If it is determined to be a directory, one of the directory types in objtype_t
// will be set to type. If it is not a directory(file, symbolic link), type will
// be set to objtype_t::UNKNOWN.
//
bool S3ObjList::insert(const char* name, const char* etag, bool is_dir)
{
if(!name || '\0' == name[0]){
return false;
}
s3obj_t::iterator iter;
std::string newname;
std::string orgname = name;
objtype_t type = objtype_t::UNKNOWN;
// Normalization
std::string::size_type pos = orgname.find("_$folder$");
if(std::string::npos != pos){
newname = orgname.substr(0, pos);
type = objtype_t::DIR_FOLDER_SUFFIX;
}else{
newname = orgname;
}
if('/' == *newname.rbegin()){
if(!IS_DIR_OBJ(type)){
type = objtype_t::DIR_NORMAL;
}
}else{
if(is_dir || IS_DIR_OBJ(type)){
newname += "/";
if(!IS_DIR_OBJ(type)){
type = objtype_t::DIR_NOT_TERMINATE_SLASH;
}
}
}
// Check derived name object.
if(is_dir || IS_DIR_OBJ(type)){
std::string chkname = newname.substr(0, newname.length() - 1);
if(objects.cend() != (iter = objects.find(chkname))){
// found "dir" object --> remove it.
objects.erase(iter);
}
}else{
std::string chkname = newname + "/";
if(objects.cend() != (iter = objects.find(chkname))){
// found "dir/" object --> not add new object.
// and add normalization
return insert_normalized(orgname.c_str(), chkname.c_str(), type);
}
}
// Add object
if(objects.cend() != (iter = objects.find(newname))){
// Found same object --> update information.
iter->second.normalname.clear();
iter->second.orgname = orgname;
iter->second.type = type;
if(etag){
iter->second.etag = etag; // over write
}
}else{
// add new object
s3obj_entry newobject;
newobject.orgname = orgname;
newobject.type = type;
if(etag){
newobject.etag = etag;
}
objects[newname] = newobject;
}
// add normalization
return insert_normalized(orgname.c_str(), newname.c_str(), type);
}
bool S3ObjList::insert_normalized(const char* name, const char* normalized, objtype_t type)
{
if(!name || '\0' == name[0] || !normalized || '\0' == normalized[0]){
return false;
}
if(0 == strcmp(name, normalized)){
return true;
}
s3obj_t::iterator iter;
if(objects.cend() != (iter = objects.find(name))){
// found name --> over write
iter->second.orgname.clear();
iter->second.etag.clear();
iter->second.normalname = normalized;
iter->second.type = type;
}else{
// not found --> add new object
s3obj_entry newobject;
newobject.normalname = normalized;
newobject.type = type;
objects[name] = newobject;
}
return true;
}
const s3obj_entry* S3ObjList::GetS3Obj(const char* name) const
{
s3obj_t::const_iterator iter;
if(!name || '\0' == name[0]){
return nullptr;
}
if(objects.cend() == (iter = objects.find(name))){
return nullptr;
}
return &(iter->second);
}
std::string S3ObjList::GetOrgName(const char* name) const
{
const s3obj_entry* ps3obj;
if(!name || '\0' == name[0]){
return "";
}
if(nullptr == (ps3obj = GetS3Obj(name))){
return "";
}
return ps3obj->orgname;
}
std::string S3ObjList::GetNormalizedName(const char* name) const
{
const s3obj_entry* ps3obj;
if(!name || '\0' == name[0]){
return "";
}
if(nullptr == (ps3obj = GetS3Obj(name))){
return "";
}
if(ps3obj->normalname.empty()){
return name;
}
return ps3obj->normalname;
}
std::string S3ObjList::GetETag(const char* name) const
{
const s3obj_entry* ps3obj;
if(!name || '\0' == name[0]){
return "";
}
if(nullptr == (ps3obj = GetS3Obj(name))){
return "";
}
return ps3obj->etag;
}
bool S3ObjList::IsDir(const char* name) const
{
const s3obj_entry* ps3obj;
if(nullptr == (ps3obj = GetS3Obj(name))){
return false;
}
return IS_DIR_OBJ(ps3obj->type);
}
bool S3ObjList::GetLastName(std::string& lastname) const
{
bool result = false;
lastname = "";
for(auto iter = objects.cbegin(); iter != objects.cend(); ++iter){
if(!iter->second.orgname.empty()){
if(lastname.compare(iter->second.orgname) < 0){
lastname = iter->second.orgname;
result = true;
}
}else{
if(lastname.compare(iter->second.normalname) < 0){
lastname = iter->second.normalname;
result = true;
}
}
}
return result;
}
bool S3ObjList::RawGetNames(s3obj_list_t* plist, s3obj_type_map_t* pobjmap, bool OnlyNormalized, bool CutSlash) const
{
if(!plist && !pobjmap){
return false;
}
for(auto iter = objects.cbegin(); objects.cend() != iter; ++iter){
if(OnlyNormalized && !iter->second.normalname.empty()){
continue;
}
std::string name = iter->first;
if(CutSlash && 1 < name.length() && '/' == *name.rbegin()){
// only "/" std::string is skipped this.
name.erase(name.length() - 1);
}
if(plist){
plist->push_back(name);
}
if(pobjmap){
(*pobjmap)[name] = iter->second.type;
}
}
return true;
}
bool S3ObjList::GetNameList(s3obj_list_t& list, bool OnlyNormalized, bool CutSlash) const
{
return RawGetNames(&list, nullptr, OnlyNormalized, CutSlash);
}
bool S3ObjList::GetNameMap(s3obj_type_map_t& objmap, bool OnlyNormalized, bool CutSlash) const
{
return RawGetNames(nullptr, &objmap, OnlyNormalized, CutSlash);
}
typedef std::map<std::string, bool> s3obj_h_t;
bool S3ObjList::MakeHierarchizedList(s3obj_list_t& list, bool haveSlash)
{
s3obj_h_t h_map;
for(auto liter = list.cbegin(); list.cend() != liter; ++liter){
std::string strtmp = (*liter);
if(1 < strtmp.length() && '/' == *strtmp.rbegin()){
strtmp.erase(strtmp.length() - 1);
}
h_map[strtmp] = true;
// check hierarchized directory
for(std::string::size_type pos = strtmp.find_last_of('/'); std::string::npos != pos; pos = strtmp.find_last_of('/')){
strtmp.erase(pos);
if(strtmp.empty() || "/" == strtmp){
break;
}
if(h_map.cend() == h_map.find(strtmp)){
// not found
h_map[strtmp] = false;
}
}
}
// check map and add lost hierarchized directory.
for(auto hiter = h_map.cbegin(); hiter != h_map.cend(); ++hiter){
if(false == (*hiter).second){
// add hierarchized directory.
std::string strtmp = (*hiter).first;
if(haveSlash){
strtmp += "/";
}
list.push_back(strtmp);
}
}
return true;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

86
src/s3objlist.h Normal file
View File

@ -0,0 +1,86 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_S3OBJLIST_H_
#define S3FS_S3OBJLIST_H_
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "types.h"
//-------------------------------------------------------------------
// Structure / Typedef
//-------------------------------------------------------------------
struct s3obj_entry{
std::string normalname; // normalized name: if empty, object is normalized name.
std::string orgname; // original name: if empty, object is original name.
std::string etag;
objtype_t type = objtype_t::UNKNOWN; // only set for directories, UNKNOWN for non-directories.
};
typedef std::map<std::string, struct s3obj_entry> s3obj_t;
typedef std::vector<std::string> s3obj_list_t;
typedef std::map<std::string, objtype_t> s3obj_type_map_t;
//-------------------------------------------------------------------
// Class S3ObjList
//-------------------------------------------------------------------
class S3ObjList
{
private:
s3obj_t objects;
std::vector<std::string> common_prefixes;
bool insert_normalized(const char* name, const char* normalized, objtype_t type);
const s3obj_entry* GetS3Obj(const char* name) const;
bool RawGetNames(s3obj_list_t* plist, s3obj_type_map_t* pobjmap, bool OnlyNormalized, bool CutSlash) const;
s3obj_t::const_iterator cbegin() const { return objects.cbegin(); }
s3obj_t::const_iterator cend() const { return objects.cend(); }
public:
bool IsEmpty() const { return objects.empty(); }
bool insert(const char* name, const char* etag = nullptr, bool is_dir = false);
std::string GetOrgName(const char* name) const;
std::string GetNormalizedName(const char* name) const;
std::string GetETag(const char* name) const;
const std::vector<std::string>& GetCommonPrefixes() const { return common_prefixes; }
void AddCommonPrefix(std::string prefix) { common_prefixes.push_back(std::move(prefix)); }
bool IsDir(const char* name) const;
bool GetNameList(s3obj_list_t& list, bool OnlyNormalized = true, bool CutSlash = true) const;
bool GetNameMap(s3obj_type_map_t& objmap, bool OnlyNormalized = true, bool CutSlash = true) const;
bool GetLastName(std::string& lastname) const;
static bool MakeHierarchizedList(s3obj_list_t& list, bool haveSlash);
};
#endif // S3FS_S3OBJLIST_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

250
src/sighandlers.cpp Normal file
View File

@ -0,0 +1,250 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#include <cstdio>
#include <csignal>
#include <memory>
#include <thread>
#include <utility>
#include "psemaphore.h"
#include "s3fs_logger.h"
#include "sighandlers.h"
#include "fdcache.h"
//-------------------------------------------------------------------
// Class S3fsSignals
//-------------------------------------------------------------------
std::unique_ptr<S3fsSignals> S3fsSignals::pSingleton;
bool S3fsSignals::enableUsr1 = false;
//-------------------------------------------------------------------
// Class methods
//-------------------------------------------------------------------
bool S3fsSignals::Initialize()
{
if(!S3fsSignals::pSingleton){
S3fsSignals::pSingleton = std::make_unique<S3fsSignals>();
}
return true;
}
bool S3fsSignals::Destroy()
{
S3fsSignals::pSingleton.reset();
return true;
}
void S3fsSignals::HandlerUSR1(int sig)
{
if(SIGUSR1 != sig){
S3FS_PRN_ERR("The handler for SIGUSR1 received signal(%d)", sig);
return;
}
S3fsSignals* pSigobj = S3fsSignals::get();
if(!pSigobj){
S3FS_PRN_ERR("S3fsSignals object is not initialized.");
return;
}
if(!pSigobj->WakeupUsr1Thread()){
S3FS_PRN_ERR("Failed to wakeup the thread for SIGUSR1.");
return;
}
}
bool S3fsSignals::SetUsr1Handler(const char* path)
{
if(!FdManager::HaveLseekHole()){
S3FS_PRN_ERR("Could not set SIGUSR1 for checking cache, because this system does not support SEEK_DATA/SEEK_HOLE in lseek function.");
return false;
}
// set output file
if(!FdManager::SetCacheCheckOutput(path)){
S3FS_PRN_ERR("Could not set output file(%s) for checking cache.", path ? path : "null(stdout)");
return false;
}
S3fsSignals::enableUsr1 = true;
return true;
}
void S3fsSignals::CheckCacheWorker(Semaphore* pSem)
{
if(!pSem){
return;
}
if(!S3fsSignals::enableUsr1){
return;
}
// wait and loop
while(S3fsSignals::enableUsr1){
// wait
pSem->acquire();
// cppcheck-suppress unmatchedSuppression
// cppcheck-suppress knownConditionTrueFalse
if(!S3fsSignals::enableUsr1){
break; // asap
}
// check all cache
if(!FdManager::get()->CheckAllCache()){
S3FS_PRN_ERR("Processing failed due to some problem.");
}
// do not allow request queuing
while(pSem->try_acquire());
}
}
void S3fsSignals::HandlerUSR2(int sig)
{
if(SIGUSR2 == sig){
S3fsLog::BumpupLogLevel();
}else{
S3FS_PRN_ERR("The handler for SIGUSR2 received signal(%d)", sig);
}
}
bool S3fsSignals::InitUsr2Handler()
{
struct sigaction sa{};
sa.sa_handler = S3fsSignals::HandlerUSR2;
sa.sa_flags = SA_RESTART;
if(0 != sigaction(SIGUSR2, &sa, nullptr)){
return false;
}
return true;
}
void S3fsSignals::HandlerHUP(int sig)
{
if(SIGHUP == sig){
S3fsLog::ReopenLogfile();
}else{
S3FS_PRN_ERR("The handler for SIGHUP received signal(%d)", sig);
}
}
bool S3fsSignals::InitHupHandler()
{
struct sigaction sa{};
sa.sa_handler = S3fsSignals::HandlerHUP;
sa.sa_flags = SA_RESTART;
if(0 != sigaction(SIGHUP, &sa, nullptr)){
return false;
}
return true;
}
//-------------------------------------------------------------------
// Methods
//-------------------------------------------------------------------
S3fsSignals::S3fsSignals()
{
if(S3fsSignals::enableUsr1){
if(!InitUsr1Handler()){
S3FS_PRN_ERR("failed creating thread for SIGUSR1 handler, but continue...");
}
}
if(!S3fsSignals::InitUsr2Handler()){
S3FS_PRN_ERR("failed to initialize SIGUSR2 handler for bumping log level, but continue...");
}
if(!S3fsSignals::InitHupHandler()){
S3FS_PRN_ERR("failed to initialize SIGHUP handler for reopen log file, but continue...");
}
}
S3fsSignals::~S3fsSignals()
{
if(S3fsSignals::enableUsr1){
if(!DestroyUsr1Handler()){
S3FS_PRN_ERR("failed stopping thread for SIGUSR1 handler, but continue...");
}
}
}
bool S3fsSignals::InitUsr1Handler()
{
if(pThreadUsr1 || pSemUsr1){
S3FS_PRN_ERR("Already run thread for SIGUSR1");
return false;
}
// create thread
auto pSemUsr1_tmp = std::make_unique<Semaphore>(0);
pThreadUsr1 = std::make_unique<std::thread>(S3fsSignals::CheckCacheWorker, pSemUsr1_tmp.get());
pSemUsr1 = std::move(pSemUsr1_tmp);
// set handler
struct sigaction sa{};
sa.sa_handler = S3fsSignals::HandlerUSR1;
sa.sa_flags = SA_RESTART;
if(0 != sigaction(SIGUSR1, &sa, nullptr)){
S3FS_PRN_ERR("Could not set signal handler for SIGUSR1");
DestroyUsr1Handler();
return false;
}
return true;
}
bool S3fsSignals::DestroyUsr1Handler()
{
if(!pThreadUsr1 || !pSemUsr1){
return false;
}
// for thread exit
S3fsSignals::enableUsr1 = false;
// wakeup thread
pSemUsr1->release();
// wait for thread exiting
pThreadUsr1->join();
pSemUsr1.reset();
pThreadUsr1.reset();
return true;
}
bool S3fsSignals::WakeupUsr1Thread()
{
if(!pThreadUsr1 || !pSemUsr1){
S3FS_PRN_ERR("The thread for SIGUSR1 is not setup.");
return false;
}
pSemUsr1->release();
return true;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

80
src/sighandlers.h Normal file
View File

@ -0,0 +1,80 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_SIGHANDLERS_H_
#define S3FS_SIGHANDLERS_H_
#include <memory>
#include <thread>
#include "psemaphore.h"
//----------------------------------------------
// class S3fsSignals
//----------------------------------------------
class S3fsSignals
{
private:
static std::unique_ptr<S3fsSignals> pSingleton;
static bool enableUsr1;
std::unique_ptr<std::thread> pThreadUsr1;
std::unique_ptr<Semaphore> pSemUsr1;
protected:
static S3fsSignals* get() { return pSingleton.get(); }
static void HandlerUSR1(int sig);
static void CheckCacheWorker(Semaphore* pSem);
static void HandlerUSR2(int sig);
static bool InitUsr2Handler();
static void HandlerHUP(int sig);
static bool InitHupHandler();
bool InitUsr1Handler();
bool DestroyUsr1Handler();
bool WakeupUsr1Thread();
public:
S3fsSignals();
~S3fsSignals();
S3fsSignals(const S3fsSignals&) = delete;
S3fsSignals(S3fsSignals&&) = delete;
S3fsSignals& operator=(const S3fsSignals&) = delete;
S3fsSignals& operator=(S3fsSignals&&) = delete;
static bool Initialize();
static bool Destroy();
static bool SetUsr1Handler(const char* path);
};
#endif // S3FS_SIGHANDLERS_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

View File

@ -1,7 +1,7 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright 2007-2008 Randy Rizun <rrizun@gmail.com>
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -17,354 +17,650 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cerrno>
#include <climits>
#include <iomanip>
#include <sstream>
#include <string>
#include <map>
#include <utility>
#include <fcntl.h>
#include <sys/stat.h>
#include "common.h"
#include "s3fs_logger.h"
#include "string_util.h"
using namespace std;
static const char hexAlphabet[] = "0123456789ABCDEF";
off_t s3fs_strtoofft(const char* str, bool is_base_16)
//-------------------------------------------------------------------
// Functions
//-------------------------------------------------------------------
std::string str(const struct timespec& value)
{
if(!str || '\0' == *str){
return 0;
}
off_t result;
bool chk_space;
bool chk_base16_prefix;
for(result = 0, chk_space = false, chk_base16_prefix = false; '\0' != *str; str++){
// check head space
if(!chk_space && isspace(*str)){
continue;
}else if(!chk_space){
chk_space = true;
std::ostringstream s;
if(UTIME_OMIT == value.tv_nsec){
s << "UTIME_OMIT";
}else if(UTIME_NOW == value.tv_nsec){
s << "UTIME_NOW";
}else{
s << value.tv_sec;
if(value.tv_nsec != 0){
s << "." << std::setfill('0') << std::setw(9) << value.tv_nsec;
}
}
// check prefix for base 16
if(!chk_base16_prefix){
chk_base16_prefix = true;
if('0' == *str && ('x' == str[1] || 'X' == str[1])){
is_base_16 = true;
str++;
continue;
}
return s.str();
}
// This source code is from https://gist.github.com/jeremyfromearth/5694aa3a66714254752179ecf3c95582 .
const char* s3fs_strptime(const char* s, const char* f, struct tm* tm)
{
std::istringstream input(s);
// TODO: call to setlocale required?
input.imbue(std::locale(setlocale(LC_ALL, nullptr)));
input >> std::get_time(tm, f);
if (input.fail()) {
return nullptr;
}
// check like isalnum and set data
result *= (is_base_16 ? 16 : 10);
if('0' <= *str || '9' < *str){
result += static_cast<off_t>(*str - '0');
}else if(is_base_16){
if('A' <= *str && *str <= 'F'){
result += static_cast<off_t>(*str - 'A' + 0x0a);
}else if('a' <= *str && *str <= 'f'){
result += static_cast<off_t>(*str - 'a' + 0x0a);
}else{
return s + input.tellg();
}
bool s3fs_strtoofft(off_t* value, const char* str, int base)
{
if(value == nullptr || str == nullptr){
return false;
}
errno = 0;
char *temp;
long long result = strtoll(str, &temp, base);
if(temp == str || *temp != '\0'){
return false;
}
if((result == LLONG_MIN || result == LLONG_MAX) && errno == ERANGE){
return false;
}
*value = result;
return true;
}
off_t cvt_strtoofft(const char* str, int base)
{
off_t result = 0;
if(!s3fs_strtoofft(&result, str, base)){
S3FS_PRN_WARN("something error is occurred in convert std::string(%s) to off_t, thus return 0 as default.", (str ? str : "null"));
return 0;
}
}
return result;
}
std::string lower(std::string s)
{
std::transform(s.cbegin(), s.cend(), s.begin(), ::tolower);
return s;
}
std::string upper(std::string s)
{
std::transform(s.cbegin(), s.cend(), s.begin(), ::toupper);
return s;
}
std::string trim_left(std::string d, const char *t /* = SPACES */)
{
return d.erase(0, d.find_first_not_of(t));
}
std::string trim_right(std::string d, const char *t /* = SPACES */)
{
std::string::size_type i(d.find_last_not_of(t));
if(i == std::string::npos){
return "";
}else{
return 0;
return d.erase(d.find_last_not_of(t) + 1);
}
}
return result;
}
string lower(string s)
std::string trim(std::string s, const char *t /* = SPACES */)
{
// change each character of the string to lower case
for(unsigned int i = 0; i < s.length(); i++){
s[i] = tolower(s[i]);
}
return s;
return trim_left(trim_right(std::move(s), t), t);
}
string trim_left(const string &s, const string &t /* = SPACES */)
std::string peeloff(std::string s)
{
string d(s);
return d.erase(0, s.find_first_not_of(t));
}
string trim_right(const string &s, const string &t /* = SPACES */)
{
string d(s);
string::size_type i(d.find_last_not_of(t));
if(i == string::npos){
return "";
}else{
return d.erase(d.find_last_not_of(t) + 1);
}
}
string trim(const string &s, const string &t /* = SPACES */)
{
string d(s);
return trim_left(trim_right(d, t), t);
}
/**
* urlEncode a fuse path,
* taking into special consideration "/",
* otherwise regular urlEncode.
*/
string urlEncode(const string &s)
{
string result;
for (unsigned i = 0; i < s.length(); ++i) {
char c = s[i];
if (c == '/' // Note- special case for fuse paths...
|| c == '.'
|| c == '-'
|| c == '_'
|| c == '~'
|| (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9')) {
result += c;
} else {
result += "%";
result += hexAlphabet[static_cast<unsigned char>(c) / 16];
result += hexAlphabet[static_cast<unsigned char>(c) % 16];
if(s.size() < 2 || *s.cbegin() != '"' || *s.rbegin() != '"'){
return s;
}
}
return result;
s.erase(s.size() - 1);
s.erase(0, 1);
return s;
}
/**
* urlEncode a fuse path,
* taking into special consideration "/",
* otherwise regular urlEncode.
*/
string urlEncode2(const string &s)
//
// Three url encode functions
//
// urlEncodeGeneral: A general URL encoding function.
// urlEncodePath : A function that URL encodes by excluding the path
// separator('/').
// urlEncodeQuery : A function that does URL encoding by excluding
// some characters('=', '&' and '%').
// This function can be used when the target string
// contains already URL encoded strings. It also
// excludes the character () used in query strings.
// Therefore, it is a function to use as URL encoding
// for use in query strings.
//
static constexpr char encode_general_except_chars[] = ".-_~"; // For general URL encode
static constexpr char encode_path_except_chars[] = ".-_~/"; // For fuse(included path) URL encode
static constexpr char encode_query_except_chars[] = ".-_~=&%"; // For query params(and encoded string)
static std::string rawUrlEncode(const std::string &s, const char* except_chars)
{
string result;
for (unsigned i = 0; i < s.length(); ++i) {
char c = s[i];
if (c == '=' // Note- special case for fuse paths...
|| c == '&' // Note- special case for s3...
|| c == '%'
|| c == '.'
|| c == '-'
|| c == '_'
|| c == '~'
|| (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9')) {
result += c;
} else {
result += "%";
result += hexAlphabet[static_cast<unsigned char>(c) / 16];
result += hexAlphabet[static_cast<unsigned char>(c) % 16];
std::string result;
for (size_t i = 0; i < s.length(); ++i) {
unsigned char c = s[i];
if((except_chars && nullptr != strchr(except_chars, c)) ||
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') )
{
result += c;
}else{
result += "%";
result += s3fs_hex_upper(&c, 1);
}
}
}
return result;
return result;
}
string urlDecode(const string& s)
std::string urlEncodeGeneral(const std::string &s)
{
string result;
for(unsigned i = 0; i < s.length(); ++i){
if(s[i] != '%'){
result += s[i];
}else{
char ch = 0;
if(s.length() <= ++i){
break; // wrong format.
}
ch += ('0' <= s[i] && s[i] <= '9') ? (s[i] - '0') : ('A' <= s[i] && s[i] <= 'F') ? (s[i] - 'A' + 0x0a) : ('a' <= s[i] && s[i] <= 'f') ? (s[i] - 'a' + 0x0a) : 0x00;
if(s.length() <= ++i){
break; // wrong format.
}
ch *= 16;
ch += ('0' <= s[i] && s[i] <= '9') ? (s[i] - '0') : ('A' <= s[i] && s[i] <= 'F') ? (s[i] - 'A' + 0x0a) : ('a' <= s[i] && s[i] <= 'f') ? (s[i] - 'a' + 0x0a) : 0x00;
result += ch;
}
}
return result;
return rawUrlEncode(s, encode_general_except_chars);
}
bool takeout_str_dquart(string& str)
std::string urlEncodePath(const std::string &s)
{
size_t pos;
return rawUrlEncode(s, encode_path_except_chars);
}
// '"' for start
if(string::npos != (pos = str.find_first_of("\""))){
str = str.substr(pos + 1);
std::string urlEncodeQuery(const std::string &s)
{
return rawUrlEncode(s, encode_query_except_chars);
}
// '"' for end
if(string::npos == (pos = str.find_last_of("\""))){
return false;
std::string urlDecode(const std::string& s)
{
std::string result;
for(size_t i = 0; i < s.length(); ++i){
if(s[i] != '%'){
result += s[i];
}else{
int ch = 0;
if(s.length() <= ++i){
break; // wrong format.
}
ch += ('0' <= s[i] && s[i] <= '9') ? (s[i] - '0') : ('A' <= s[i] && s[i] <= 'F') ? (s[i] - 'A' + 0x0a) : ('a' <= s[i] && s[i] <= 'f') ? (s[i] - 'a' + 0x0a) : 0x00;
if(s.length() <= ++i){
break; // wrong format.
}
ch *= 16;
ch += ('0' <= s[i] && s[i] <= '9') ? (s[i] - '0') : ('A' <= s[i] && s[i] <= 'F') ? (s[i] - 'A' + 0x0a) : ('a' <= s[i] && s[i] <= 'f') ? (s[i] - 'a' + 0x0a) : 0x00;
result += static_cast<char>(ch);
}
}
str = str.substr(0, pos);
if(string::npos != str.find_first_of("\"")){
return false;
return result;
}
bool takeout_str_dquart(std::string& str)
{
size_t pos;
// '"' for start
if(std::string::npos != (pos = str.find_first_of('\"'))){
str.erase(0, pos + 1);
// '"' for end
if(std::string::npos == (pos = str.find_last_of('\"'))){
return false;
}
str.erase(pos);
if(std::string::npos != str.find_first_of('\"')){
return false;
}
}
}
return true;
return true;
}
//
// ex. target="http://......?keyword=value&..."
//
bool get_keyword_value(string& target, const char* keyword, string& value)
bool get_keyword_value(const std::string& target, const char* keyword, std::string& value)
{
if(!keyword){
return false;
}
size_t spos;
size_t epos;
if(string::npos == (spos = target.find(keyword))){
return false;
}
spos += strlen(keyword);
if('=' != target.at(spos)){
return false;
}
spos++;
if(string::npos == (epos = target.find('&', spos))){
value = target.substr(spos);
}else{
value = target.substr(spos, (epos - spos));
}
return true;
}
/**
* Returns the current date
* in a format suitable for a HTTP request header.
*/
string get_date_rfc850()
{
char buf[100];
time_t t = time(NULL);
strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t));
return buf;
}
void get_date_sigv3(string& date, string& date8601)
{
time_t tm = time(NULL);
date = get_date_string(tm);
date8601 = get_date_iso8601(tm);
}
string get_date_string(time_t tm)
{
char buf[100];
strftime(buf, sizeof(buf), "%Y%m%d", gmtime(&tm));
return buf;
}
string get_date_iso8601(time_t tm)
{
char buf[100];
strftime(buf, sizeof(buf), "%Y%m%dT%H%M%SZ", gmtime(&tm));
return buf;
}
std::string s3fs_hex(const unsigned char* input, size_t length)
{
std::string hex;
for(size_t pos = 0; pos < length; ++pos){
char hexbuf[3];
snprintf(hexbuf, 3, "%02x", input[pos]);
hex += hexbuf;
}
return hex;
}
char* s3fs_base64(const unsigned char* input, size_t length)
{
static const char* base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
char* result;
if(!input || 0 >= length){
return NULL;
}
if(NULL == (result = (char*)malloc((((length / 3) + 1) * 4 + 1) * sizeof(char)))){
return NULL; // ENOMEM
}
unsigned char parts[4];
size_t rpos;
size_t wpos;
for(rpos = 0, wpos = 0; rpos < length; rpos += 3){
parts[0] = (input[rpos] & 0xfc) >> 2;
parts[1] = ((input[rpos] & 0x03) << 4) | ((((rpos + 1) < length ? input[rpos + 1] : 0x00) & 0xf0) >> 4);
parts[2] = (rpos + 1) < length ? (((input[rpos + 1] & 0x0f) << 2) | ((((rpos + 2) < length ? input[rpos + 2] : 0x00) & 0xc0) >> 6)) : 0x40;
parts[3] = (rpos + 2) < length ? (input[rpos + 2] & 0x3f) : 0x40;
result[wpos++] = base[parts[0]];
result[wpos++] = base[parts[1]];
result[wpos++] = base[parts[2]];
result[wpos++] = base[parts[3]];
}
result[wpos] = '\0';
return result;
}
inline unsigned char char_decode64(const char ch)
{
unsigned char by;
if('A' <= ch && ch <= 'Z'){ // A - Z
by = static_cast<unsigned char>(ch - 'A');
}else if('a' <= ch && ch <= 'z'){ // a - z
by = static_cast<unsigned char>(ch - 'a' + 26);
}else if('0' <= ch && ch <= '9'){ // 0 - 9
by = static_cast<unsigned char>(ch - '0' + 52);
}else if('+' == ch){ // +
by = 62;
}else if('/' == ch){ // /
by = 63;
}else if('=' == ch){ // =
by = 64;
}else{ // something wrong
by = UCHAR_MAX;
}
return by;
}
unsigned char* s3fs_decode64(const char* input, size_t* plength)
{
unsigned char* result;
if(!input || 0 == strlen(input) || !plength){
return NULL;
}
if(NULL == (result = (unsigned char*)malloc((strlen(input) + 1)))){
return NULL; // ENOMEM
}
unsigned char parts[4];
size_t input_len = strlen(input);
size_t rpos;
size_t wpos;
for(rpos = 0, wpos = 0; rpos < input_len; rpos += 4){
parts[0] = char_decode64(input[rpos]);
parts[1] = (rpos + 1) < input_len ? char_decode64(input[rpos + 1]) : 64;
parts[2] = (rpos + 2) < input_len ? char_decode64(input[rpos + 2]) : 64;
parts[3] = (rpos + 3) < input_len ? char_decode64(input[rpos + 3]) : 64;
result[wpos++] = ((parts[0] << 2) & 0xfc) | ((parts[1] >> 4) & 0x03);
if(64 == parts[2]){
break;
if(!keyword){
return false;
}
result[wpos++] = ((parts[1] << 4) & 0xf0) | ((parts[2] >> 2) & 0x0f);
if(64 == parts[3]){
break;
size_t spos;
size_t epos;
if(std::string::npos == (spos = target.find(keyword))){
return false;
}
result[wpos++] = ((parts[2] << 6) & 0xc0) | (parts[3] & 0x3f);
}
result[wpos] = '\0';
*plength = wpos;
return result;
spos += strlen(keyword);
if('=' != target[spos]){
return false;
}
spos++;
if(std::string::npos == (epos = target.find('&', spos))){
value = target.substr(spos);
}else{
value = target.substr(spos, (epos - spos));
}
return true;
}
//
// Returns the current date
// in a format suitable for a HTTP request header.
//
std::string get_date_rfc850()
{
char buf[100];
time_t t = time(nullptr);
struct tm res;
strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S GMT", gmtime_r(&t, &res));
return buf;
}
void get_date_sigv3(std::string& date, std::string& date8601)
{
time_t tm = time(nullptr);
date = get_date_string(tm);
date8601 = get_date_iso8601(tm);
}
std::string get_date_string(time_t tm)
{
char buf[100];
struct tm res;
strftime(buf, sizeof(buf), "%Y%m%d", gmtime_r(&tm, &res));
return buf;
}
std::string get_date_iso8601(time_t tm)
{
char buf[100];
struct tm res;
strftime(buf, sizeof(buf), "%Y%m%dT%H%M%SZ", gmtime_r(&tm, &res));
return buf;
}
bool get_unixtime_from_iso8601(const char* pdate, time_t& unixtime)
{
if(!pdate){
return false;
}
struct tm tm;
const char* prest = s3fs_strptime(pdate, "%Y-%m-%dT%T", &tm);
if(prest == pdate){
// wrong format
return false;
}
unixtime = mktime(&tm);
return true;
}
//
// Convert to unixtime from std::string which formatted by following:
// "12Y12M12D12h12m12s", "86400s", "9h30m", etc
//
bool convert_unixtime_from_option_arg(const char* argv, time_t& unixtime)
{
if(!argv){
return false;
}
unixtime = 0;
const char* ptmp;
int last_unit_type = 0; // unit flag.
bool is_last_number;
time_t tmptime;
for(ptmp = argv, is_last_number = true, tmptime = 0; ptmp && *ptmp; ++ptmp){
if('0' <= *ptmp && *ptmp <= '9'){
tmptime *= 10;
tmptime += static_cast<time_t>(*ptmp - '0');
is_last_number = true;
}else if(is_last_number){
if('Y' == *ptmp && 1 > last_unit_type){
unixtime += (tmptime * (60 * 60 * 24 * 365)); // average 365 day / year
last_unit_type = 1;
}else if('M' == *ptmp && 2 > last_unit_type){
unixtime += (tmptime * (60 * 60 * 24 * 30)); // average 30 day / month
last_unit_type = 2;
}else if('D' == *ptmp && 3 > last_unit_type){
unixtime += (tmptime * (60 * 60 * 24));
last_unit_type = 3;
}else if('h' == *ptmp && 4 > last_unit_type){
unixtime += (tmptime * (60 * 60));
last_unit_type = 4;
}else if('m' == *ptmp && 5 > last_unit_type){
unixtime += (tmptime * 60);
last_unit_type = 5;
}else if('s' == *ptmp && 6 > last_unit_type){
unixtime += tmptime;
last_unit_type = 6;
}else{
return false;
}
tmptime = 0;
is_last_number = false;
}else{
return false;
}
}
if(is_last_number){
return false;
}
return true;
}
static std::string s3fs_hex(const unsigned char* input, size_t length, const char *hexAlphabet)
{
std::string hex;
for(size_t pos = 0; pos < length; ++pos){
hex += hexAlphabet[input[pos] / 16];
hex += hexAlphabet[input[pos] % 16];
}
return hex;
}
std::string s3fs_hex_lower(const unsigned char* input, size_t length)
{
return s3fs_hex(input, length, "0123456789abcdef");
}
std::string s3fs_hex_upper(const unsigned char* input, size_t length)
{
return s3fs_hex(input, length, "0123456789ABCDEF");
}
std::string s3fs_base64(const unsigned char* input, size_t length)
{
static constexpr char base[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
std::string result;
result.reserve(((length + 3 - 1) / 3) * 4 + 1);
unsigned char parts[4];
size_t rpos;
for(rpos = 0; rpos < length; rpos += 3){
parts[0] = (input[rpos] & 0xfc) >> 2;
parts[1] = ((input[rpos] & 0x03) << 4) | ((((rpos + 1) < length ? input[rpos + 1] : 0x00) & 0xf0) >> 4);
parts[2] = (rpos + 1) < length ? (((input[rpos + 1] & 0x0f) << 2) | ((((rpos + 2) < length ? input[rpos + 2] : 0x00) & 0xc0) >> 6)) : 0x40;
parts[3] = (rpos + 2) < length ? (input[rpos + 2] & 0x3f) : 0x40;
result += base[parts[0]];
result += base[parts[1]];
result += base[parts[2]];
result += base[parts[3]];
}
return result;
}
static constexpr unsigned char char_decode64(const char ch)
{
if('A' <= ch && ch <= 'Z'){ // A - Z
return static_cast<unsigned char>(ch - 'A');
}else if('a' <= ch && ch <= 'z'){ // a - z
return static_cast<unsigned char>(ch - 'a' + 26);
}else if('0' <= ch && ch <= '9'){ // 0 - 9
return static_cast<unsigned char>(ch - '0' + 52);
}else if('+' == ch){ // +
return 62;
}else if('/' == ch){ // /
return 63;
}else if('=' == ch){ // =
return 64;
}else{ // something wrong
return UCHAR_MAX;
}
}
std::string s3fs_decode64(const char* input, size_t input_len)
{
std::string result;
result.reserve(input_len / 4 * 3);
unsigned char parts[4];
size_t rpos;
for(rpos = 0; rpos < input_len; rpos += 4){
parts[0] = char_decode64(input[rpos]);
parts[1] = (rpos + 1) < input_len ? char_decode64(input[rpos + 1]) : 64;
parts[2] = (rpos + 2) < input_len ? char_decode64(input[rpos + 2]) : 64;
parts[3] = (rpos + 3) < input_len ? char_decode64(input[rpos + 3]) : 64;
result += static_cast<char>(((parts[0] << 2) & 0xfc) | ((parts[1] >> 4) & 0x03));
if(64 == parts[2]){
break;
}
result += static_cast<char>(((parts[1] << 4) & 0xf0) | ((parts[2] >> 2) & 0x0f));
if(64 == parts[3]){
break;
}
result += static_cast<char>(((parts[2] << 6) & 0xc0) | (parts[3] & 0x3f));
}
return result;
}
//
// detect and rewrite invalid utf8. We take invalid bytes
// and encode them into a private region of the unicode
// space. This is sometimes known as wtf8, wobbly transformation format.
// it is necessary because S3 validates the utf8 used for identifiers for
// correctness, while some clients may provide invalid utf, notably
// windows using cp1252.
//
// Base location for transform. The range 0xE000 - 0xF8ff
// is a private range, se use the start of this range.
static constexpr unsigned int escape_base = 0xe000;
// encode bytes into wobbly utf8.
// 'result' can be null. returns true if transform was needed.
bool s3fs_wtf8_encode(const char *s, std::string *result)
{
bool invalid = false;
// Pass valid utf8 code through
for (; *s; s++) {
const unsigned char c = *s;
// single byte encoding
if (c <= 0x7f) {
if (result) {
*result += c;
}
continue;
}
// otherwise, it must be one of the valid start bytes
if ( c >= 0xc2 && c <= 0xf5 ) {
// two byte encoding
// don't need bounds check, std::string is zero terminated
if ((c & 0xe0) == 0xc0 && (s[1] & 0xc0) == 0x80) {
// all two byte encodings starting higher than c1 are valid
if (result) {
*result += c;
*result += *(++s);
}
continue;
}
// three byte encoding
if ((c & 0xf0) == 0xe0 && (s[1] & 0xc0) == 0x80 && (s[2] & 0xc0) == 0x80) {
const unsigned code = ((c & 0x0f) << 12) | ((s[1] & 0x3f) << 6) | (s[2] & 0x3f);
if (code >= 0x800 && ! (code >= 0xd800 && code <= 0xd8ff)) {
// not overlong and not a surrogate pair
if (result) {
*result += c;
*result += *(++s);
*result += *(++s);
}
continue;
}
}
// four byte encoding
if ((c & 0xf8) == 0xf0 && (s[1] & 0xc0) == 0x80 && (s[2] & 0xc0) == 0x80 && (s[3] & 0xc0) == 0x80) {
const unsigned code = ((c & 0x07) << 18) | ((s[1] & 0x3f) << 12) | ((s[2] & 0x3f) << 6) | (s[3] & 0x3f);
if (code >= 0x10'000 && code <= 0x10f'fff) {
// not overlong and in defined unicode space
if (result) {
*result += c;
*result += *(++s);
*result += *(++s);
*result += *(++s);
}
continue;
}
}
}
// printf("invalid %02x at %d\n", c, i);
// Invalid utf8 code. Convert it to a private two byte area of unicode
// e.g. the e000 - f8ff area. This will be a three byte encoding
invalid = true;
if (result) {
unsigned escape = escape_base + c;
*result += static_cast<char>(0xe0 | ((escape >> 12) & 0x0f));
*result += static_cast<char>(0x80 | ((escape >> 06) & 0x3f));
*result += static_cast<char>(0x80 | ((escape >> 00) & 0x3f));
}
}
return invalid;
}
std::string s3fs_wtf8_encode(const std::string &s)
{
std::string result;
s3fs_wtf8_encode(s.c_str(), &result);
return result;
}
// The reverse operation, turn encoded bytes back into their original values
// The code assumes that we map to a three-byte code point.
bool s3fs_wtf8_decode(const char *s, std::string *result)
{
bool encoded = false;
for (; *s; s++) {
unsigned char c = *s;
// look for a three byte tuple matching our encoding code
if ((c & 0xf0) == 0xe0 && (s[1] & 0xc0) == 0x80 && (s[2] & 0xc0) == 0x80) {
unsigned code = (c & 0x0f) << 12;
code |= (s[1] & 0x3f) << 6;
code |= (s[2] & 0x3f) << 0;
if (code >= escape_base && code <= escape_base + 0xff) {
// convert back
encoded = true;
if(result){
*result += static_cast<char>(code - escape_base);
}
s+=2;
continue;
}
}
if (result) {
*result += c;
}
}
return encoded;
}
std::string s3fs_wtf8_decode(const std::string &s)
{
std::string result;
s3fs_wtf8_decode(s.c_str(), &result);
return result;
}
//
// Encode only CR('\r'=0x0D) and it also encodes the '%' character accordingly.
//
// The xmlReadMemory() function in libxml2 replaces CR code with LF code('\n'=0x0A)
// due to the XML specification.
// s3fs uses libxml2 to parse the S3 response, and this automatic substitution
// of libxml2 may change the object name(file/dir name). Therefore, before passing
// the response to the xmlReadMemory() function, we need the string encoded by
// this function.
//
// [NOTE]
// Normally the quotes included in the XML content data are HTML encoded("&quot;").
// Encoding for CR can also be HTML encoded as binary code (ex, "&#13;"), but
// if the same string content(as file name) as this encoded string exists, the
// original string cannot be distinguished whichever encoded or not encoded.
// Therefore, CR is encoded in the same manner as URL encoding("%0A").
// And it is assumed that there is no CR code in the S3 response tag etc.(actually
// it shouldn't exist)
//
std::string get_encoded_cr_code(const char* pbase)
{
std::string result;
if(!pbase){
return result;
}
std::string strbase(pbase);
size_t baselength = strbase.length();
size_t startpos = 0;
size_t foundpos;
while(startpos < baselength && std::string::npos != (foundpos = strbase.find_first_of("%\r", startpos))){
if(0 < (foundpos - startpos)){
result += strbase.substr(startpos, foundpos - startpos);
}
if('%' == strbase[foundpos]){
result += "%45";
}else if('\r' == strbase[foundpos]){
result += "%0D";
}
startpos = foundpos + 1;
}
if(startpos < baselength){
result += strbase.substr(startpos);
}
return result;
}
//
// Decode a string encoded with get_encoded_cr_code().
//
std::string get_decoded_cr_code(const char* pencode)
{
std::string result;
if(!pencode){
return result;
}
std::string strencode(pencode);
size_t encodelength = strencode.length();
size_t startpos = 0;
size_t foundpos;
while(startpos < encodelength && std::string::npos != (foundpos = strencode.find('%', startpos))){
if(0 < (foundpos - startpos)){
result += strencode.substr(startpos, foundpos - startpos);
}
if((foundpos + 2) < encodelength && 0 == strencode.compare(foundpos, 3, "%45")){
result += '%';
startpos = foundpos + 3;
}else if((foundpos + 2) < encodelength && 0 == strencode.compare(foundpos, 3, "%0D")){
result += '\r';
startpos = foundpos + 3;
}else if((foundpos + 1) < encodelength && 0 == strencode.compare(foundpos, 2, "%%")){
result += '%';
startpos = foundpos + 2;
}else{
result += '%';
startpos = foundpos + 1;
}
}
if(startpos < encodelength){
result += strencode.substr(startpos);
}
return result;
}
/*
@ -372,6 +668,6 @@ unsigned char* s3fs_decode64(const char* input, size_t* plength)
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

View File

@ -1,7 +1,7 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright 2007-2008 Randy Rizun <rrizun@gmail.com>
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -17,47 +17,121 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef S3FS_STRING_UTIL_H_
#define S3FS_STRING_UTIL_H_
/*
* A collection of string utilities for manipulating URLs and HTTP responses.
*/
#include <string.h>
#include <syslog.h>
#include <sys/types.h>
#include <cstring>
#include <ctime>
#include <string>
#include <sstream>
#include <strings.h>
#define SPACES " \t\r\n"
#define STR2NCMP(str1, str2) strncmp(str1, str2, strlen(str2))
//
// A collection of string utilities for manipulating URLs and HTTP responses.
//
//-------------------------------------------------------------------
// Global variables
//-------------------------------------------------------------------
static constexpr char SPACES[] = " \t\r\n";
template<typename T> std::string str(T value) {
std::stringstream s;
s << value;
return s.str();
}
//-------------------------------------------------------------------
// Inline functions
//-------------------------------------------------------------------
class CaseInsensitiveStringView {
public:
explicit CaseInsensitiveStringView(const std::string &str) : str(str.c_str()) {}
bool operator==(const char *other) const { return strcasecmp(str, other) == 0; }
bool is_prefix(const char *prefix) const { return strncasecmp(str, prefix, strlen(prefix)) == 0; }
private:
const char *str;
};
static inline bool is_prefix(const char *str, const char *prefix) { return strncmp(str, prefix, strlen(prefix)) == 0; }
static inline const char* SAFESTRPTR(const char *strptr) { return strptr ? strptr : ""; }
off_t s3fs_strtoofft(const char* str, bool is_base_16 = false);
//-------------------------------------------------------------------
// Macros(WTF8)
//-------------------------------------------------------------------
#define WTF8_ENCODE(ARG) \
std::string ARG##_buf; \
const char * ARG = _##ARG; \
if (use_wtf8 && s3fs_wtf8_encode( _##ARG, 0 )) { \
s3fs_wtf8_encode( _##ARG, &ARG##_buf); \
ARG = ARG##_buf.c_str(); \
}
std::string trim_left(const std::string &s, const std::string &t = SPACES);
std::string trim_right(const std::string &s, const std::string &t = SPACES);
std::string trim(const std::string &s, const std::string &t = SPACES);
//-------------------------------------------------------------------
// Utilities
//-------------------------------------------------------------------
// TODO: rename to to_string?
std::string str(const struct timespec& value);
//
// Cross-platform strptime
//
const char* s3fs_strptime(const char* s, const char* f, struct tm* tm);
//
// Convert string to off_t. Returns false on bad input.
// Replacement for C++11 std::stoll.
//
bool s3fs_strtoofft(off_t* value, const char* str, int base = 0);
//
// This function returns 0 if a value that cannot be converted is specified.
// Only call if 0 is considered an error and the operation can continue.
//
off_t cvt_strtoofft(const char* str, int base);
//
// String Manipulation
//
std::string trim_left(std::string s, const char *t = SPACES);
std::string trim_right(std::string s, const char *t = SPACES);
std::string trim(std::string s, const char *t = SPACES);
std::string lower(std::string s);
std::string get_date_rfc850(void);
std::string upper(std::string s);
std::string peeloff(std::string s);
//
// Date string
//
std::string get_date_rfc850();
void get_date_sigv3(std::string& date, std::string& date8601);
std::string get_date_string(time_t tm);
std::string get_date_iso8601(time_t tm);
std::string urlEncode(const std::string &s);
std::string urlEncode2(const std::string &s);
std::string urlDecode(const std::string& s);
bool takeout_str_dquart(std::string& str);
bool get_keyword_value(std::string& target, const char* keyword, std::string& value);
bool get_unixtime_from_iso8601(const char* pdate, time_t& unixtime);
bool convert_unixtime_from_option_arg(const char* argv, time_t& unixtime);
std::string s3fs_hex(const unsigned char* input, size_t length);
char* s3fs_base64(const unsigned char* input, size_t length);
unsigned char* s3fs_decode64(const char* input, size_t* plength);
//
// For encoding
//
std::string urlEncodeGeneral(const std::string &s);
std::string urlEncodePath(const std::string &s);
std::string urlEncodeQuery(const std::string &s);
std::string urlDecode(const std::string& s);
bool takeout_str_dquart(std::string& str);
bool get_keyword_value(const std::string& target, const char* keyword, std::string& value);
//
// For binary string
//
std::string s3fs_hex_lower(const unsigned char* input, size_t length);
std::string s3fs_hex_upper(const unsigned char* input, size_t length);
std::string s3fs_base64(const unsigned char* input, size_t length);
std::string s3fs_decode64(const char* input, size_t input_len);
//
// WTF8
//
bool s3fs_wtf8_encode(const char *s, std::string *result);
std::string s3fs_wtf8_encode(const std::string &s);
bool s3fs_wtf8_decode(const char *s, std::string *result);
std::string s3fs_wtf8_decode(const std::string &s);
//
// For CR in XML
//
std::string get_encoded_cr_code(const char* pbase);
std::string get_decoded_cr_code(const char* pencode);
#endif // S3FS_STRING_UTIL_H_
@ -66,6 +140,6 @@ unsigned char* s3fs_decode64(const char* input, size_t* plength);
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

74
src/syncfiller.cpp Normal file
View File

@ -0,0 +1,74 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#include <cstdio>
#include <cstdlib>
#include "s3fs_logger.h"
#include "syncfiller.h"
//-------------------------------------------------------------------
// Class SyncFiller
//-------------------------------------------------------------------
SyncFiller::SyncFiller(void* buff, fuse_fill_dir_t filler) : filler_buff(buff), filler_func(filler)
{
if(!filler_buff || !filler_func){
S3FS_PRN_CRIT("Internal error: SyncFiller constructor parameter is critical value.");
abort();
}
}
//
// See. prototype fuse_fill_dir_t in fuse.h
//
int SyncFiller::Fill(const std::string& name, const struct stat *stbuf, off_t off)
{
const std::lock_guard<std::mutex> lock(filler_lock);
int result = 0;
if(filled.insert(name).second){
result = filler_func(filler_buff, name.c_str(), stbuf, off);
}
return result;
}
int SyncFiller::SufficiencyFill(const std::vector<std::string>& pathlist)
{
const std::lock_guard<std::mutex> lock(filler_lock);
int result = 0;
for(auto it = pathlist.cbegin(); it != pathlist.cend(); ++it) {
if(filled.insert(*it).second){
if(0 != filler_func(filler_buff, it->c_str(), nullptr, 0)){
result = 1;
}
}
}
return result;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

67
src/syncfiller.h Normal file
View File

@ -0,0 +1,67 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef SYNCFILLER_H_
#define SYNCFILLER_H_
#include <string>
#include <mutex>
#include <vector>
#include <set>
#include "s3fs.h"
//----------------------------------------------
// class SyncFiller
//----------------------------------------------
//
// A synchronous class that calls the fuse_fill_dir_t
// function that processes the readdir data
//
class SyncFiller
{
private:
mutable std::mutex filler_lock;
void* filler_buff;
fuse_fill_dir_t filler_func;
std::set<std::string> filled;
public:
explicit SyncFiller(void* buff = nullptr, fuse_fill_dir_t filler = nullptr);
~SyncFiller() = default;
SyncFiller(const SyncFiller&) = delete;
SyncFiller(SyncFiller&&) = delete;
SyncFiller& operator=(const SyncFiller&) = delete;
SyncFiller& operator=(SyncFiller&&) = delete;
int Fill(const std::string& name, const struct stat *stbuf, off_t off);
int SufficiencyFill(const std::vector<std::string>& pathlist);
};
#endif // SYNCFILLER_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

167
src/test_curl_util.cpp Normal file
View File

@ -0,0 +1,167 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2020 Andrew Gaul <andrew@gaul.org>
*
* 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.
*/
#include <string>
#include <cstring>
#include "curl_util.h"
#include "test_util.h"
//---------------------------------------------------------
// S3fsCred Stub
//
// [NOTE]
// This test program links curl_util.cpp just to use the
// curl_slist_sort_insert function.
// This file has a call to S3fsCred::GetBucket(), which
// results in a link error. That method is not used in
// this test file, so define a stub class. Linking all
// implementation of the S3fsCred class or making all
// stubs is not practical, so this is the best answer.
//
class S3fsCred
{
private:
static std::string bucket_name;
public:
static const std::string& GetBucket();
};
std::string S3fsCred::bucket_name;
const std::string& S3fsCred::GetBucket()
{
return S3fsCred::bucket_name;
}
//---------------------------------------------------------
#define ASSERT_IS_SORTED(x) assert_is_sorted((x), __FILE__, __LINE__)
void assert_is_sorted(const struct curl_slist* list, const char *file, int line)
{
for(; list != nullptr; list = list->next){
std::string key1 = list->data;
key1.erase(key1.find(':'));
std::string key2 = list->data;
key2.erase(key2.find(':'));
std::cerr << "key1: " << key1 << " key2: " << key2 << std::endl;
if(strcasecmp(key1.c_str(), key2.c_str()) > 0){
std::cerr << "not sorted: " << key1 << " " << key2 << " at " << file << ":" << line << std::endl;
std::exit(1);
}
}
std::cerr << std::endl;
}
size_t curl_slist_length(const struct curl_slist* list)
{
size_t len = 0;
for(; list != nullptr; list = list->next){
++len;
}
return len;
}
void test_sort_insert()
{
struct curl_slist* list = nullptr;
ASSERT_IS_SORTED(list);
// add to head
list = curl_slist_sort_insert(list, "2", "val");
ASSERT_IS_SORTED(list);
// add to tail
list = curl_slist_sort_insert(list, "4", "val");
ASSERT_IS_SORTED(list);
// add in between
list = curl_slist_sort_insert(list, "3", "val");
ASSERT_IS_SORTED(list);
// add to head
list = curl_slist_sort_insert(list, "1", "val");
ASSERT_IS_SORTED(list);
ASSERT_STREQUALS("1: val", list->data);
// replace head
list = curl_slist_sort_insert(list, "1", "val2");
ASSERT_IS_SORTED(list);
ASSERT_EQUALS(static_cast<size_t>(4), curl_slist_length(list));
ASSERT_STREQUALS("1: val2", list->data);
curl_slist_free_all(list);
}
void test_slist_remove()
{
struct curl_slist* list = nullptr;
// remove no elements
ASSERT_EQUALS(static_cast<size_t>(0), curl_slist_length(list));
list = curl_slist_remove(list, "1");
ASSERT_EQUALS(static_cast<size_t>(0), curl_slist_length(list));
// remove only element
list = nullptr;
list = curl_slist_sort_insert(list, "1", "val");
ASSERT_EQUALS(static_cast<size_t>(1), curl_slist_length(list));
list = curl_slist_remove(list, "1");
ASSERT_EQUALS(static_cast<size_t>(0), curl_slist_length(list));
// remove head element
list = nullptr;
list = curl_slist_sort_insert(list, "1", "val");
list = curl_slist_sort_insert(list, "2", "val");
ASSERT_EQUALS(static_cast<size_t>(2), curl_slist_length(list));
list = curl_slist_remove(list, "1");
ASSERT_EQUALS(static_cast<size_t>(1), curl_slist_length(list));
curl_slist_free_all(list);
// remove tail element
list = nullptr;
list = curl_slist_sort_insert(list, "1", "val");
list = curl_slist_sort_insert(list, "2", "val");
ASSERT_EQUALS(static_cast<size_t>(2), curl_slist_length(list));
list = curl_slist_remove(list, "2");
ASSERT_EQUALS(static_cast<size_t>(1), curl_slist_length(list));
curl_slist_free_all(list);
// remove middle element
list = nullptr;
list = curl_slist_sort_insert(list, "1", "val");
list = curl_slist_sort_insert(list, "2", "val");
list = curl_slist_sort_insert(list, "3", "val");
ASSERT_EQUALS(static_cast<size_t>(3), curl_slist_length(list));
list = curl_slist_remove(list, "2");
ASSERT_EQUALS(static_cast<size_t>(2), curl_slist_length(list));
curl_slist_free_all(list);
}
int main(int argc, const char *argv[])
{
test_sort_insert();
test_slist_remove();
return 0;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

80
src/test_page_list.cpp Normal file
View File

@ -0,0 +1,80 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2021 Andrew Gaul <andrew@gaul.org>
*
* 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.
*/
#include "fdcache_page.h"
#include "fdcache_stat.h"
#include "test_util.h"
bool CacheFileStat::Open() { return false; } // NOLINT(readability-convert-member-functions-to-static)
bool CacheFileStat::OverWriteFile(const std::string& strall) const { return false; } // NOLINT(readability-convert-member-functions-to-static)
void test_compress()
{
PageList list;
ASSERT_EQUALS(off_t(0), list.Size());
list.Init(42, /*is_loaded=*/ false, /*is_modified=*/ false);
ASSERT_EQUALS(off_t(42), list.Size());
ASSERT_FALSE(list.IsPageLoaded(0, 1));
list.SetPageLoadedStatus(0, 1, /*pstatus=*/ PageList::page_status::LOADED);
ASSERT_TRUE(list.IsPageLoaded(0, 1));
ASSERT_FALSE(list.IsPageLoaded(0, 2));
off_t start = 0;
off_t size = 0;
ASSERT_TRUE(list.FindUnloadedPage(0, start, size));
ASSERT_EQUALS(off_t(1), start);
ASSERT_EQUALS(off_t(41), size);
// test adding subsequent page then compressing
list.SetPageLoadedStatus(1, 3, /*pstatus=*/ PageList::page_status::LOADED);
list.Compress();
ASSERT_TRUE(list.IsPageLoaded(0, 3));
ASSERT_TRUE(list.FindUnloadedPage(0, start, size));
ASSERT_EQUALS(off_t(4), start);
ASSERT_EQUALS(off_t(38), size);
// test adding non-contiguous page then compressing
list.SetPageLoadedStatus(5, 1, /*pstatus=*/ PageList::page_status::LOADED);
list.Compress();
ASSERT_TRUE(list.FindUnloadedPage(0, start, size));
ASSERT_EQUALS(off_t(4), start);
ASSERT_EQUALS(off_t(1), size);
list.Dump();
printf("\n");
// test adding page between two pages then compressing
list.SetPageLoadedStatus(4, 1, /*pstatus=*/ PageList::page_status::LOADED);
list.Compress();
list.Dump();
ASSERT_TRUE(list.FindUnloadedPage(0, start, size));
ASSERT_EQUALS(off_t(6), start);
ASSERT_EQUALS(off_t(36), size);
}
int main(int argc, const char *argv[])
{
test_compress();
return 0;
}

View File

@ -1,7 +1,7 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright 2014 Andrew Gaul <andrew@gaul.org>
* Copyright(C) 2014 Andrew Gaul <andrew@gaul.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -18,66 +18,205 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <cstdint>
#include <cstdlib>
#include <limits>
#include <stdint.h>
#include <string>
#include "s3fs_logger.h"
#include "string_util.h"
#include "test_util.h"
using namespace std::string_literals;
//-------------------------------------------------------------------
// Global variables for test_string_util
//-------------------------------------------------------------------
bool foreground = false;
std::string instance_name;
void test_trim()
{
ASSERT_EQUALS(std::string("1234"), trim(" 1234 "));
ASSERT_EQUALS(std::string("1234"), trim("1234 "));
ASSERT_EQUALS(std::string("1234"), trim(" 1234"));
ASSERT_EQUALS(std::string("1234"), trim("1234"));
ASSERT_EQUALS("1234"s, trim(" 1234 "));
ASSERT_EQUALS("1234"s, trim("1234 "));
ASSERT_EQUALS("1234"s, trim(" 1234"));
ASSERT_EQUALS("1234"s, trim("1234"));
ASSERT_EQUALS(std::string("1234 "), trim_left(" 1234 "));
ASSERT_EQUALS(std::string("1234 "), trim_left("1234 "));
ASSERT_EQUALS(std::string("1234"), trim_left(" 1234"));
ASSERT_EQUALS(std::string("1234"), trim_left("1234"));
ASSERT_EQUALS("1234 "s, trim_left(" 1234 "));
ASSERT_EQUALS("1234 "s, trim_left("1234 "));
ASSERT_EQUALS("1234"s, trim_left(" 1234"));
ASSERT_EQUALS("1234"s, trim_left("1234"));
ASSERT_EQUALS(std::string(" 1234"), trim_right(" 1234 "));
ASSERT_EQUALS(std::string("1234"), trim_right("1234 "));
ASSERT_EQUALS(std::string(" 1234"), trim_right(" 1234"));
ASSERT_EQUALS(std::string("1234"), trim_right("1234"));
ASSERT_EQUALS(" 1234"s, trim_right(" 1234 "));
ASSERT_EQUALS("1234"s, trim_right("1234 "));
ASSERT_EQUALS(" 1234"s, trim_right(" 1234"));
ASSERT_EQUALS("1234"s, trim_right("1234"));
ASSERT_EQUALS(std::string("0"), str(0));
ASSERT_EQUALS(std::string("1"), str(1));
ASSERT_EQUALS(std::string("-1"), str(-1));
ASSERT_EQUALS(std::string("9223372036854775807"), str(std::numeric_limits<int64_t>::max()));
ASSERT_EQUALS(std::string("-9223372036854775808"), str(std::numeric_limits<int64_t>::min()));
ASSERT_EQUALS(std::string("0"), str(std::numeric_limits<uint64_t>::min()));
ASSERT_EQUALS(std::string("18446744073709551615"), str(std::numeric_limits<uint64_t>::max()));
ASSERT_EQUALS("1234"s, peeloff("\"1234\"")); // "1234" -> 1234
ASSERT_EQUALS("\"1234\""s, peeloff("\"\"1234\"\"")); // ""1234"" -> "1234"
ASSERT_EQUALS("\"1234"s, peeloff("\"\"1234\"")); // ""1234" -> "1234
ASSERT_EQUALS("1234\""s, peeloff("\"1234\"\"")); // "1234"" -> 1234"
ASSERT_EQUALS("\"1234"s, peeloff("\"1234")); // "1234 -> "1234
ASSERT_EQUALS("1234\""s, peeloff("1234\"")); // 1234" -> 1234"
ASSERT_EQUALS(" \"1234\""s, peeloff(" \"1234\"")); // _"1234" -> _"1234"
ASSERT_EQUALS("\"1234\" "s, peeloff("\"1234\" ")); // "1234"_ -> "1234"_
}
void test_base64()
{
size_t len;
ASSERT_STREQUALS(s3fs_base64(NULL, 0), NULL);
ASSERT_STREQUALS(reinterpret_cast<const char *>(s3fs_decode64(NULL, &len)), NULL);
ASSERT_STREQUALS(s3fs_base64(reinterpret_cast<const unsigned char *>(""), 0), NULL);
ASSERT_STREQUALS(reinterpret_cast<const char *>(s3fs_decode64("", &len)), NULL);
std::string buf;
char tmpbuf = '\0';
ASSERT_STREQUALS(s3fs_base64(reinterpret_cast<const unsigned char *>("1"), 1), "MQ==");
ASSERT_STREQUALS(reinterpret_cast<const char *>(s3fs_decode64("MQ==", &len)), "1");
ASSERT_EQUALS(len, static_cast<size_t>(1));
ASSERT_STREQUALS(s3fs_base64(reinterpret_cast<const unsigned char *>("12"), 2), "MTI=");
ASSERT_STREQUALS(reinterpret_cast<const char *>(s3fs_decode64("MTI=", &len)), "12");
ASSERT_EQUALS(len, static_cast<size_t>(2));
ASSERT_STREQUALS(s3fs_base64(reinterpret_cast<const unsigned char *>("123"), 3), "MTIz");
ASSERT_STREQUALS(reinterpret_cast<const char *>(s3fs_decode64("MTIz", &len)), "123");
ASSERT_EQUALS(len, static_cast<size_t>(3));
ASSERT_STREQUALS(s3fs_base64(reinterpret_cast<const unsigned char *>("1234"), 4), "MTIzNA==");
ASSERT_STREQUALS(reinterpret_cast<const char *>(s3fs_decode64("MTIzNA==", &len)), "1234");
ASSERT_EQUALS(len, static_cast<size_t>(4));
ASSERT_EQUALS(s3fs_base64(nullptr, 0), ""s);
buf = s3fs_decode64(nullptr, 0);
ASSERT_BUFEQUALS(buf.c_str(), buf.length(), &tmpbuf, 0);
// TODO: invalid input
ASSERT_EQUALS(s3fs_base64(reinterpret_cast<const unsigned char *>(""), 0), ""s);
buf = s3fs_decode64("", 0);
ASSERT_BUFEQUALS(buf.c_str(), buf.length(), &tmpbuf, 0);
ASSERT_EQUALS(s3fs_base64(reinterpret_cast<const unsigned char *>("1"), 1), "MQ=="s);
buf = s3fs_decode64("MQ==", 4);
ASSERT_BUFEQUALS(buf.c_str(), buf.length(), "1", 1);
ASSERT_EQUALS(buf.length(), static_cast<size_t>(1));
ASSERT_EQUALS(s3fs_base64(reinterpret_cast<const unsigned char *>("12"), 2), "MTI="s);
buf = s3fs_decode64("MTI=", 4);
ASSERT_BUFEQUALS(buf.c_str(), buf.length(), "12", 2);
ASSERT_EQUALS(buf.length(), static_cast<size_t>(2));
ASSERT_EQUALS(s3fs_base64(reinterpret_cast<const unsigned char *>("123"), 3), "MTIz"s);
buf = s3fs_decode64("MTIz", 4);
ASSERT_BUFEQUALS(buf.c_str(), buf.length(), "123", 3);
ASSERT_EQUALS(buf.length(), static_cast<size_t>(3));
ASSERT_EQUALS(s3fs_base64(reinterpret_cast<const unsigned char *>("1234"), 4), "MTIzNA=="s);
buf = s3fs_decode64("MTIzNA==", 8);
ASSERT_BUFEQUALS(buf.c_str(), buf.length(), "1234", 4);
ASSERT_EQUALS(buf.length(), static_cast<size_t>(4));
// TODO: invalid input
}
int main(int argc, char *argv[])
void test_strtoofft()
{
test_trim();
test_base64();
return 0;
off_t value;
ASSERT_TRUE(s3fs_strtoofft(&value, "0"));
ASSERT_EQUALS(value, static_cast<off_t>(0L));
ASSERT_TRUE(s3fs_strtoofft(&value, "9"));
ASSERT_EQUALS(value, static_cast<off_t>(9L));
ASSERT_FALSE(s3fs_strtoofft(&value, "A"));
ASSERT_TRUE(s3fs_strtoofft(&value, "A", /*base=*/ 16));
ASSERT_EQUALS(value, static_cast<off_t>(10L));
ASSERT_TRUE(s3fs_strtoofft(&value, "F", /*base=*/ 16));
ASSERT_EQUALS(value, static_cast<off_t>(15L));
ASSERT_TRUE(s3fs_strtoofft(&value, "a", /*base=*/ 16));
ASSERT_EQUALS(value, static_cast<off_t>(10L));
ASSERT_TRUE(s3fs_strtoofft(&value, "f", /*base=*/ 16));
ASSERT_EQUALS(value, static_cast<off_t>(15L));
ASSERT_TRUE(s3fs_strtoofft(&value, "deadbeef", /*base=*/ 16));
ASSERT_EQUALS(value, static_cast<off_t>(3'735'928'559L));
}
void test_wtf8_encoding()
{
std::string ascii("normal std::string");
std::string utf8("Hyld\xc3\xbdpi \xc3\xbej\xc3\xb3\xc3\xb0""f\xc3\xa9lagsins vex \xc3\xbar k\xc3\xa6rkomnu b\xc3\xb6li \xc3\xad \xc3\xa1st");
std::string cp1252("Hyld\xfdpi \xfej\xf3\xf0""f\xe9lagsins vex \xfar k\xe6rkomnu b\xf6li \xed \xe1st");
std::string broken = utf8;
broken[14] = '\x97';
std::string mixed = ascii + utf8 + cp1252;
ASSERT_EQUALS(s3fs_wtf8_encode(ascii), ascii);
ASSERT_EQUALS(s3fs_wtf8_decode(ascii), ascii);
ASSERT_EQUALS(s3fs_wtf8_encode(utf8), utf8);
ASSERT_EQUALS(s3fs_wtf8_decode(utf8), utf8);
ASSERT_NEQUALS(s3fs_wtf8_encode(cp1252), cp1252);
ASSERT_EQUALS(s3fs_wtf8_decode(s3fs_wtf8_encode(cp1252)), cp1252);
ASSERT_NEQUALS(s3fs_wtf8_encode(broken), broken);
ASSERT_EQUALS(s3fs_wtf8_decode(s3fs_wtf8_encode(broken)), broken);
ASSERT_NEQUALS(s3fs_wtf8_encode(mixed), mixed);
ASSERT_EQUALS(s3fs_wtf8_decode(s3fs_wtf8_encode(mixed)), mixed);
}
void test_cr_encoding()
{
// bse strings
std::string base_no("STR");
std::string base_end_cr1("STR\r");
std::string base_mid_cr1("STR\rSTR");
std::string base_end_cr2("STR\r\r");
std::string base_mid_cr2("STR\r\rSTR");
std::string base_end_per1("STR%");
std::string base_mid_per1("STR%STR");
std::string base_end_per2("STR%%");
std::string base_mid_per2("STR%%STR");
std::string base_end_crlf1("STR\r\n");
std::string base_mid_crlf1("STR\r\nSTR");
std::string base_end_crlf2("STR\r\n\r\n");
std::string base_mid_crlf2("STR\r\n\r\nSTR");
std::string base_end_crper1("STR%\r");
std::string base_mid_crper1("STR%\rSTR");
std::string base_end_crper2("STR%\r%\r");
std::string base_mid_crper2("STR%\r%\rSTR");
// encode->decode->compare
ASSERT_EQUALS(get_decoded_cr_code(get_encoded_cr_code(base_no.c_str()).c_str()), base_no);
ASSERT_EQUALS(get_decoded_cr_code(get_encoded_cr_code(base_end_cr1.c_str()).c_str()), base_end_cr1);
ASSERT_EQUALS(get_decoded_cr_code(get_encoded_cr_code(base_mid_cr1.c_str()).c_str()), base_mid_cr1);
ASSERT_EQUALS(get_decoded_cr_code(get_encoded_cr_code(base_end_cr2.c_str()).c_str()), base_end_cr2);
ASSERT_EQUALS(get_decoded_cr_code(get_encoded_cr_code(base_mid_cr2.c_str()).c_str()), base_mid_cr2);
ASSERT_EQUALS(get_decoded_cr_code(get_encoded_cr_code(base_end_per1.c_str()).c_str()), base_end_per1);
ASSERT_EQUALS(get_decoded_cr_code(get_encoded_cr_code(base_mid_per1.c_str()).c_str()), base_mid_per1);
ASSERT_EQUALS(get_decoded_cr_code(get_encoded_cr_code(base_end_per2.c_str()).c_str()), base_end_per2);
ASSERT_EQUALS(get_decoded_cr_code(get_encoded_cr_code(base_mid_per2.c_str()).c_str()), base_mid_per2);
ASSERT_EQUALS(get_decoded_cr_code(get_encoded_cr_code(base_end_crlf1.c_str()).c_str()), base_end_crlf1);
ASSERT_EQUALS(get_decoded_cr_code(get_encoded_cr_code(base_mid_crlf1.c_str()).c_str()), base_mid_crlf1);
ASSERT_EQUALS(get_decoded_cr_code(get_encoded_cr_code(base_end_crlf2.c_str()).c_str()), base_end_crlf2);
ASSERT_EQUALS(get_decoded_cr_code(get_encoded_cr_code(base_mid_crlf2.c_str()).c_str()), base_mid_crlf2);
ASSERT_EQUALS(get_decoded_cr_code(get_encoded_cr_code(base_end_crper1.c_str()).c_str()), base_end_crper1);
ASSERT_EQUALS(get_decoded_cr_code(get_encoded_cr_code(base_mid_crper1.c_str()).c_str()), base_mid_crper1);
ASSERT_EQUALS(get_decoded_cr_code(get_encoded_cr_code(base_end_crper2.c_str()).c_str()), base_end_crper2);
ASSERT_EQUALS(get_decoded_cr_code(get_encoded_cr_code(base_mid_crper2.c_str()).c_str()), base_mid_crper2);
}
int main(int argc, const char *argv[])
{
S3fsLog singletonLog;
test_trim();
test_base64();
test_strtoofft();
test_wtf8_encoding();
test_cr_encoding();
return 0;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

View File

@ -1,7 +1,7 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright 2014 Andrew Gaul <andrew@gaul.org>
* Copyright(C) 2014 Andrew Gaul <andrew@gaul.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -18,29 +18,90 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef S3FS_TEST_UTIL_H_
#define S3FS_TEST_UTIL_H_
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
template <typename T> void assert_equals(const T &x, const T &y, const char *file, int line)
#include "string_util.h"
template <typename T> inline void assert_equals(const T &x, const T &y, const char *file, int line)
{
if (x != y) {
std::cerr << x << " != " << y << " at " << file << ":" << line << std::endl;
std::exit(1);
if (x != y) {
std::cerr << x << " != " << y << " at " << file << ":" << line << std::endl;
std::cerr << std::endl;
abort();
}
}
template <> inline void assert_equals(const std::string &x, const std::string &y, const char *file, int line)
{
if (x != y) {
std::cerr << x << " != " << y << " at " << file << ":" << line << std::endl;
std::cerr << s3fs_hex_lower(reinterpret_cast<const unsigned char *>(x.c_str()), x.size()) << std::endl;
std::cerr << s3fs_hex_lower(reinterpret_cast<const unsigned char *>(y.c_str()), y.size()) << std::endl;
abort();
}
}
template <typename T> inline void assert_nequals(const T &x, const T &y, const char *file, int line)
{
if (x == y) {
std::cerr << x << " == " << y << " at " << file << ":" << line << std::endl;
abort();
}
}
template <> inline void assert_nequals(const std::string &x, const std::string &y, const char *file, int line)
{
if (x == y) {
std::cerr << x << " == " << y << " at " << file << ":" << line << std::endl;
std::cerr << s3fs_hex_lower(reinterpret_cast<const unsigned char *>(x.c_str()), x.size()) << std::endl;
std::cerr << s3fs_hex_lower(reinterpret_cast<const unsigned char *>(y.c_str()), y.size()) << std::endl;
abort();
}
}
inline void assert_strequals(const char *x, const char *y, const char *file, int line)
{
if(x == nullptr && y == nullptr){
return;
// cppcheck-suppress nullPointerRedundantCheck
} else if(x == nullptr || y == nullptr || strcmp(x, y) != 0){
std::cerr << (x ? x : "null") << " != " << (y ? y : "null") << " at " << file << ":" << line << std::endl;
abort();
}
}
void assert_strequals(const char *x, const char *y, const char *file, int line)
inline void assert_bufequals(const char *x, size_t len1, const char *y, size_t len2, const char *file, int line)
{
if(x == NULL && y == NULL){
return;
} else if((x == NULL || y == NULL) || strcmp(x, y) != 0){
std::cerr << x << " != " << y << " at " << file << ":" << line << std::endl;
std::exit(1);
}
if(x == nullptr && y == nullptr){
return;
// cppcheck-suppress nullPointerRedundantCheck
} else if(x == nullptr || y == nullptr || len1 != len2 || memcmp(x, y, len1) != 0){
std::cerr << (x ? std::string(x, len1) : "null") << " != " << (y ? std::string(y, len2) : "null") << " at " << file << ":" << line << std::endl;
abort();
}
}
#define ASSERT_EQUALS(x, y) \
assert_equals((x), (y), __FILE__, __LINE__)
#define ASSERT_TRUE(x) assert_equals((x), true, __FILE__, __LINE__)
#define ASSERT_FALSE(x) assert_equals((x), false, __FILE__, __LINE__)
#define ASSERT_EQUALS(x, y) assert_equals((x), (y), __FILE__, __LINE__)
#define ASSERT_NEQUALS(x, y) assert_nequals((x), (y), __FILE__, __LINE__)
#define ASSERT_STREQUALS(x, y) assert_strequals((x), (y), __FILE__, __LINE__)
#define ASSERT_BUFEQUALS(x, len1, y, len2) assert_bufequals((x), (len1), (y), (len2), __FILE__, __LINE__)
#define ASSERT_STREQUALS(x, y) \
assert_strequals((x), (y), __FILE__, __LINE__)
#endif // S3FS_TEST_UTIL_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

296
src/threadpoolman.cpp Normal file
View File

@ -0,0 +1,296 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Takeshi Nakatani <ggtakec.com>
*
* 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.
*/
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <future>
#include <mutex>
#include <thread>
#include <utility>
#include "s3fs_logger.h"
#include "threadpoolman.h"
#include "curl.h"
#include "curl_share.h"
//------------------------------------------------
// ThreadPoolMan class variables
//------------------------------------------------
int ThreadPoolMan::worker_count = 10; // default
std::unique_ptr<ThreadPoolMan> ThreadPoolMan::singleton;
//------------------------------------------------
// ThreadPoolMan class methods
//------------------------------------------------
bool ThreadPoolMan::Initialize(int count)
{
if(ThreadPoolMan::singleton){
S3FS_PRN_CRIT("Already singleton for Thread Manager exists.");
abort();
}
if(-1 != count){
ThreadPoolMan::SetWorkerCount(count);
}
ThreadPoolMan::singleton = std::make_unique<ThreadPoolMan>(ThreadPoolMan::worker_count);
return true;
}
void ThreadPoolMan::Destroy()
{
ThreadPoolMan::singleton.reset();
}
int ThreadPoolMan::SetWorkerCount(int count)
{
if(0 >= count){
S3FS_PRN_ERR("Thread worker count(%d) must be positive number.", count);
return -1;
}
if(count == ThreadPoolMan::worker_count){
return ThreadPoolMan::worker_count;
}
// [TODO]
// If we need to dynamically change worker threads, this is
// where we would terminate/add workers.
//
int old = ThreadPoolMan::worker_count;
ThreadPoolMan::worker_count = count;
return old;
}
bool ThreadPoolMan::Instruct(const thpoolman_param& param)
{
if(!ThreadPoolMan::singleton){
S3FS_PRN_WARN("The singleton object is not initialized yet.");
return false;
}
if(!param.psem){
S3FS_PRN_ERR("Thread parameter Semaphore is null.");
return false;
}
ThreadPoolMan::singleton->SetInstruction(param);
return true;
}
bool ThreadPoolMan::AwaitInstruct(const thpoolman_param& param)
{
if(!ThreadPoolMan::singleton){
S3FS_PRN_WARN("The singleton object is not initialized yet.");
return false;
}
if(param.psem){
S3FS_PRN_ERR("Thread parameter Semaphore must be null.");
return false;
}
// Setup local thpoolman_param structure with local Semaphore
thpoolman_param local_param;
Semaphore await_sem(0);
local_param.args = param.args;
local_param.psem = &await_sem;
local_param.pfunc = param.pfunc;
// Set parameters and run thread worker
ThreadPoolMan::singleton->SetInstruction(local_param);
// wait until the thread is complete
await_sem.acquire();
return true;
}
//
// Thread worker
//
void ThreadPoolMan::Worker(ThreadPoolMan* psingleton, std::promise<int> promise)
{
if(!psingleton){
S3FS_PRN_ERR("The parameter for worker thread is invalid.");
promise.set_value(-EIO);
return;
}
S3FS_PRN_INFO3("Start worker thread in ThreadPoolMan.");
// The only object in this thread worker
S3fsCurl s3fscurl(true);
while(!psingleton->IsExit()){
// wait
psingleton->thpoolman_sem.acquire();
if(psingleton->IsExit()){
break;
}
// reset curl handle
if(!s3fscurl.CreateCurlHandle(true)){
S3FS_PRN_ERR("Failed to re-create curl handle.");
break;
}
// get instruction
thpoolman_param param;
{
const std::lock_guard<std::mutex> lock(psingleton->thread_list_lock);
if(psingleton->instruction_list.empty()){
S3FS_PRN_DBG("Got a semaphore, but the instruction is empty.");
continue;
}else{
param = psingleton->instruction_list.front();
psingleton->instruction_list.pop_front();
}
}
// run function
void* retval;
if(nullptr != (retval = param.pfunc(s3fscurl, param.args))){
S3FS_PRN_WARN("The instruction function returned with something error code(%ld).", reinterpret_cast<long>(retval));
}
if(param.psem){
param.psem->release();
}
}
if(!S3fsCurlShare::DestroyCurlShareHandleForThread()){
S3FS_PRN_WARN("Failed to destroy curl share handle for this thread, but continue...");
}
promise.set_value(0);
}
//------------------------------------------------
// ThreadPoolMan methods
//------------------------------------------------
ThreadPoolMan::ThreadPoolMan(int count) : is_exit(false), thpoolman_sem(0)
{
if(count < 1){
S3FS_PRN_CRIT("Failed to creating singleton for Thread Manager, because thread count(%d) is under 1.", count);
abort();
}
if(ThreadPoolMan::singleton){
S3FS_PRN_CRIT("Already singleton for Thread Manager exists.");
abort();
}
// create threads
if(!StartThreads(count)){
S3FS_PRN_ERR("Failed starting threads at initializing.");
abort();
}
}
ThreadPoolMan::~ThreadPoolMan()
{
StopThreads();
}
bool ThreadPoolMan::IsExit() const
{
return is_exit;
}
void ThreadPoolMan::SetExitFlag(bool exit_flag)
{
is_exit = exit_flag;
}
bool ThreadPoolMan::StopThreads()
{
const std::lock_guard<std::mutex> lock(thread_list_lock);
if(thread_list.empty()){
S3FS_PRN_INFO("Any threads are running now, then nothing to do.");
return true;
}
// all threads to exit
SetExitFlag(true);
for(size_t waitcnt = thread_list.size(); 0 < waitcnt; --waitcnt){
thpoolman_sem.release();
}
// wait for threads exiting
for(auto& pair : thread_list){
pair.first.join();
long retval = pair.second.get();
S3FS_PRN_DBG("join succeeded - return code(%ld)", reinterpret_cast<long>(retval));
}
thread_list.clear();
// reset semaphore(to zero)
while(thpoolman_sem.try_acquire()){
}
return true;
}
bool ThreadPoolMan::StartThreads(int count)
{
if(count < 1){
S3FS_PRN_ERR("Failed to creating threads, because thread count(%d) is under 1.", count);
return false;
}
// stop all thread if they are running.
// cppcheck-suppress unmatchedSuppression
// cppcheck-suppress knownConditionTrueFalse
if(!StopThreads()){
S3FS_PRN_ERR("Failed to stop existed threads.");
return false;
}
// create all threads
SetExitFlag(false);
for(int cnt = 0; cnt < count; ++cnt){
// run thread
std::promise<int> promise;
std::future<int> future = promise.get_future();
std::thread thread(ThreadPoolMan::Worker, this, std::move(promise));
const std::lock_guard<std::mutex> lock(thread_list_lock);
thread_list.emplace_back(std::move(thread), std::move(future));
}
return true;
}
void ThreadPoolMan::SetInstruction(const thpoolman_param& param)
{
// set parameter to list
{
const std::lock_guard<std::mutex> lock(thread_list_lock);
instruction_list.push_back(param);
}
// run thread
thpoolman_sem.release();
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

111
src/threadpoolman.h Normal file
View File

@ -0,0 +1,111 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_THREADPOOLMAN_H_
#define S3FS_THREADPOOLMAN_H_
#include <atomic>
#include <future>
#include <list>
#include <mutex>
#include <vector>
#include "common.h"
#include "psemaphore.h"
//------------------------------------------------
// Typedefs for functions and structures
//------------------------------------------------
class S3fsCurl;
//
// Prototype function
//
typedef void* (*thpoolman_worker)(S3fsCurl&, void*);
//
// Parameter structure
//
// [NOTE]
// The args member is a value that is an argument of the worker function.
// The psem member is allowed nullptr. If it is not nullptr, the post() method is
// called when finishing the function.
//
struct thpoolman_param
{
void* args = nullptr;
Semaphore* psem = nullptr;
thpoolman_worker pfunc = nullptr;
};
typedef std::list<thpoolman_param> thpoolman_params_t;
//------------------------------------------------
// Class ThreadPoolMan
//------------------------------------------------
class ThreadPoolMan
{
private:
static int worker_count;
static std::unique_ptr<ThreadPoolMan> singleton;
std::atomic<bool> is_exit;
Semaphore thpoolman_sem;
std::mutex thread_list_lock;
std::vector<std::pair<std::thread, std::future<int>>> thread_list GUARDED_BY(thread_list_lock);
thpoolman_params_t instruction_list GUARDED_BY(thread_list_lock);
private:
static void Worker(ThreadPoolMan* psingleton, std::promise<int> promise);
bool IsExit() const;
void SetExitFlag(bool exit_flag);
bool StopThreads();
bool StartThreads(int count);
void SetInstruction(const thpoolman_param& pparam);
public:
explicit ThreadPoolMan(int count = 1);
~ThreadPoolMan();
ThreadPoolMan(const ThreadPoolMan&) = delete;
ThreadPoolMan(ThreadPoolMan&&) = delete;
ThreadPoolMan& operator=(const ThreadPoolMan&) = delete;
ThreadPoolMan& operator=(ThreadPoolMan&&) = delete;
static bool Initialize(int count = -1);
static void Destroy();
static int SetWorkerCount(int count);
static int GetWorkerCount() { return ThreadPoolMan::worker_count; }
static bool Instruct(const thpoolman_param& pparam);
static bool AwaitInstruct(const thpoolman_param& param);
};
#endif // S3FS_THREADPOOLMAN_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

468
src/types.h Normal file
View File

@ -0,0 +1,468 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
*
* 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.
*/
#ifndef S3FS_TYPES_H_
#define S3FS_TYPES_H_
#include <cstdlib>
#include <cstdint>
#include <cstring>
#include <string>
#include <map>
#include <list>
#include <utility>
#include <vector>
//
// For extended attribute
// (HAVE_XXX symbols are defined in config.h)
//
#ifdef HAVE_SYS_EXTATTR_H
#include <sys/extattr.h>
#elif HAVE_ATTR_XATTR_H
#include <attr/xattr.h>
#elif HAVE_SYS_XATTR_H
#include <sys/xattr.h>
#endif
//-------------------------------------------------------------------
// xattrs_t
//-------------------------------------------------------------------
//
// Header "x-amz-meta-xattr" is for extended attributes.
// This header is url encoded string which is json formatted.
// x-amz-meta-xattr:urlencode({"xattr-1":"base64(value-1)","xattr-2":"base64(value-2)","xattr-3":"base64(value-3)"})
//
typedef std::map<std::string, std::string> xattrs_t;
//-------------------------------------------------------------------
// acl_t
//-------------------------------------------------------------------
enum class acl_t : uint8_t {
PRIVATE,
PUBLIC_READ,
PUBLIC_READ_WRITE,
AWS_EXEC_READ,
AUTHENTICATED_READ,
BUCKET_OWNER_READ,
BUCKET_OWNER_FULL_CONTROL,
LOG_DELIVERY_WRITE,
UNKNOWN
};
constexpr const char* str(acl_t value)
{
switch(value){
case acl_t::PRIVATE:
return "private";
case acl_t::PUBLIC_READ:
return "public-read";
case acl_t::PUBLIC_READ_WRITE:
return "public-read-write";
case acl_t::AWS_EXEC_READ:
return "aws-exec-read";
case acl_t::AUTHENTICATED_READ:
return "authenticated-read";
case acl_t::BUCKET_OWNER_READ:
return "bucket-owner-read";
case acl_t::BUCKET_OWNER_FULL_CONTROL:
return "bucket-owner-full-control";
case acl_t::LOG_DELIVERY_WRITE:
return "log-delivery-write";
case acl_t::UNKNOWN:
return nullptr;
}
abort();
}
inline acl_t to_acl(const char *acl)
{
if(0 == strcmp(acl, "private")){
return acl_t::PRIVATE;
}else if(0 == strcmp(acl, "public-read")){
return acl_t::PUBLIC_READ;
}else if(0 == strcmp(acl, "public-read-write")){
return acl_t::PUBLIC_READ_WRITE;
}else if(0 == strcmp(acl, "aws-exec-read")){
return acl_t::AWS_EXEC_READ;
}else if(0 == strcmp(acl, "authenticated-read")){
return acl_t::AUTHENTICATED_READ;
}else if(0 == strcmp(acl, "bucket-owner-read")){
return acl_t::BUCKET_OWNER_READ;
}else if(0 == strcmp(acl, "bucket-owner-full-control")){
return acl_t::BUCKET_OWNER_FULL_CONTROL;
}else if(0 == strcmp(acl, "log-delivery-write")){
return acl_t::LOG_DELIVERY_WRITE;
}else{
return acl_t::UNKNOWN;
}
}
//-------------------------------------------------------------------
// sse_type_t
//-------------------------------------------------------------------
enum class sse_type_t : uint8_t {
SSE_DISABLE = 0, // not use server side encrypting
SSE_S3, // server side encrypting by S3 key
SSE_C, // server side encrypting by custom key
SSE_KMS // server side encrypting by kms id
};
enum class signature_type_t : uint8_t {
V2_ONLY,
V4_ONLY,
V2_OR_V4
};
//----------------------------------------------
// etaglist_t / filepart / untreatedpart
//----------------------------------------------
//
// Etag string and part number pair
//
struct etagpair
{
std::string etag; // expected etag value
int part_num; // part number
explicit etagpair(const char* petag = nullptr, int part = -1) : etag(petag ? petag : ""), part_num(part) {}
~etagpair()
{
clear();
}
void clear()
{
etag.clear();
part_num = -1;
}
};
// Requires pointer stability and thus must be a list not a vector
typedef std::list<etagpair> etaglist_t;
struct petagpool
{
// Requires pointer stability and thus must be a list not a vector
std::list<etagpair> petaglist;
~petagpool()
{
clear();
}
void clear()
{
petaglist.clear();
}
etagpair* add(const etagpair& etag_entity)
{
petaglist.push_back(etag_entity);
return &petaglist.back();
}
};
//
// Each part information for Multipart upload
//
struct filepart
{
bool uploaded = false; // does finish uploading
std::string etag; // expected etag value
int fd; // base file(temporary full file) descriptor
off_t startpos; // seek fd point for uploading
off_t size; // uploading size
bool is_copy; // whether is copy multipart
etagpair* petag; // use only parallel upload
explicit filepart(bool is_uploaded = false, int _fd = -1, off_t part_start = 0, off_t part_size = -1, bool is_copy_part = false, etagpair* petagpair = nullptr) : fd(_fd), startpos(part_start), size(part_size), is_copy(is_copy_part), petag(petagpair) {}
~filepart()
{
clear();
}
void clear()
{
uploaded = false;
etag = "";
fd = -1;
startpos = 0;
size = -1;
is_copy = false;
petag = nullptr;
}
void add_etag_list(etaglist_t& list, int partnum = -1)
{
if(-1 == partnum){
partnum = static_cast<int>(list.size()) + 1;
}
list.emplace_back(nullptr, partnum);
petag = &list.back();
}
void set_etag(etagpair* petagobj)
{
petag = petagobj;
}
int get_part_number() const
{
if(!petag){
return -1;
}
return petag->part_num;
}
};
typedef std::vector<filepart> filepart_list_t;
//
// Each part information for Untreated parts
//
struct untreatedpart
{
off_t start; // untreated start position
off_t size; // number of untreated bytes
long untreated_tag; // untreated part tag
explicit untreatedpart(off_t part_start = 0, off_t part_size = 0, long part_untreated_tag = 0) : start(part_start), size(part_size), untreated_tag(part_untreated_tag)
{
if(part_start < 0 || part_size <= 0){
clear(); // wrong parameter, so clear value.
}
}
~untreatedpart()
{
clear();
}
void clear()
{
start = 0;
size = 0;
untreated_tag = 0;
}
// [NOTE]
// Check if the areas overlap
// However, even if the areas do not overlap, this method returns true if areas are adjacent.
//
bool check_overlap(off_t chk_start, off_t chk_size) const
{
if(chk_start < 0 || chk_size <= 0 || start < 0 || size <= 0 || (chk_start + chk_size) < start || (start + size) < chk_start){
return false;
}
return true;
}
bool stretch(off_t add_start, off_t add_size, long tag)
{
if(!check_overlap(add_start, add_size)){
return false;
}
off_t new_start = std::min(start, add_start);
off_t new_next_start = std::max((start + size), (add_start + add_size));
start = new_start;
size = new_next_start - new_start;
untreated_tag = tag;
return true;
}
};
typedef std::vector<untreatedpart> untreated_list_t;
//
// Information on each part of multipart upload
//
struct mp_part
{
off_t start;
off_t size;
int part_num; // Set only for information to upload
explicit mp_part(off_t set_start = 0, off_t set_size = 0, int part = 0) : start(set_start), size(set_size), part_num(part) {}
};
typedef std::vector<struct mp_part> mp_part_list_t;
inline off_t total_mp_part_list(const mp_part_list_t& mplist)
{
off_t size = 0;
for(auto iter = mplist.cbegin(); iter != mplist.cend(); ++iter){
size += iter->size;
}
return size;
}
//
// Rename directory struct
//
struct mvnode
{
mvnode(std::string old_path, std::string new_path, bool is_dir, bool is_normdir)
: old_path(std::move(old_path))
, new_path(std::move(new_path))
, is_dir(is_dir)
, is_normdir(is_normdir)
{}
std::string old_path;
std::string new_path;
bool is_dir;
bool is_normdir;
};
//-------------------------------------------------------------------
// mimes_t
//-------------------------------------------------------------------
struct case_insensitive_compare_func
{
bool operator()(const std::string& a, const std::string& b) const {
return strcasecmp(a.c_str(), b.c_str()) < 0;
}
};
typedef std::map<std::string, std::string, case_insensitive_compare_func> mimes_t;
//-------------------------------------------------------------------
// S3 Object Type Enum : objtype_t
//-------------------------------------------------------------------
// The type defines what files, symlinks, and directories can be
// represented in S3.
// The stats cache has a negative cache, which also defines its type.
// Directory objects can have multiple types depending on the client
// that created them.
// To accommodate these, this enumeration also defines the type of the
// original object.
//
enum class objtype_t : int8_t {
UNKNOWN = -1,
FILE = 0,
SYMLINK = 1,
DIR_NORMAL = 2,
DIR_NOT_TERMINATE_SLASH = 3,
DIR_FOLDER_SUFFIX = 4,
DIR_NOT_EXIST_OBJECT = 5,
NEGATIVE = 6 // Negative type means an object does not exist in Stats cache.
};
constexpr bool IS_FILE_OBJ(objtype_t type)
{
return (objtype_t::FILE == type);
}
constexpr bool IS_SYMLINK_OBJ(objtype_t type)
{
return (objtype_t::SYMLINK == type);
}
constexpr bool IS_NORMALDIR_OBJ(objtype_t type)
{
return (objtype_t::DIR_NORMAL == type);
}
constexpr bool IS_DIR_OBJ(objtype_t type)
{
return (objtype_t::DIR_NORMAL == type || objtype_t::DIR_NOT_TERMINATE_SLASH == type || objtype_t::DIR_FOLDER_SUFFIX == type || objtype_t::DIR_NOT_EXIST_OBJECT == type);
}
constexpr bool IS_NEGATIVE_OBJ(objtype_t type)
{
return (objtype_t::NEGATIVE == type);
}
constexpr bool IS_SAME_OBJ(objtype_t type1, objtype_t type2)
{
if(type1 == type2){
return true;
}
if(IS_DIR_OBJ(type1) && IS_DIR_OBJ(type2)){
return true;
}
return false;
}
constexpr bool NEED_REPLACEDIR_OBJ(objtype_t type)
{
return (objtype_t::DIR_NOT_TERMINATE_SLASH == type || objtype_t::DIR_FOLDER_SUFFIX == type || objtype_t::DIR_NOT_EXIST_OBJECT == type);
}
constexpr bool NEED_RMDIR_OBJ(objtype_t type)
{
return (objtype_t::DIR_NOT_TERMINATE_SLASH == type || objtype_t::DIR_FOLDER_SUFFIX == type);
}
inline std::string STR_OBJTYPE(objtype_t type)
{
std::string strType;
switch(type){
case objtype_t::UNKNOWN:
strType = "UNKNOWN(" + std::to_string(static_cast<int>(type)) + ")";
break;
case objtype_t::FILE:
strType = "FILE(" + std::to_string(static_cast<int>(type)) + ")";
break;
case objtype_t::SYMLINK:
strType = "SYMLINK(" + std::to_string(static_cast<int>(type)) + ")";
break;
case objtype_t::DIR_NORMAL:
strType = "DIR_NORMAL(" + std::to_string(static_cast<int>(type)) + ")";
break;
case objtype_t::DIR_NOT_TERMINATE_SLASH:
strType = "DIR_NOT_TERMINATE_SLASH(" + std::to_string(static_cast<int>(type)) + ")";
break;
case objtype_t::DIR_FOLDER_SUFFIX:
strType = "DIR_FOLDER_SUFFIX(" + std::to_string(static_cast<int>(type)) + ")";
break;
case objtype_t::DIR_NOT_EXIST_OBJECT:
strType = "DIR_NOT_EXIST_OBJECT(" + std::to_string(static_cast<int>(type)) + ")";
break;
case objtype_t::NEGATIVE:
strType = "NEGATIVE(" + std::to_string(static_cast<int>(type)) + ")";
break;
default:
strType = "not defined value(" + std::to_string(static_cast<int>(type)) + ")";
break;
}
return strType;
}
//-------------------------------------------------------------------
// Typedefs specialized for use
//-------------------------------------------------------------------
typedef std::vector<std::string> readline_t;
typedef std::map<std::string, std::string> kvmap_t;
typedef std::map<std::string, kvmap_t> bucketkvmap_t;
#endif // S3FS_TYPES_H_
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

View File

@ -17,14 +17,45 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
######################################################################
TESTS=small-integration-test.sh
EXTRA_DIST = \
integration-test-common.sh \
require-root.sh \
small-integration-test.sh \
mergedir.sh \
sample_delcache.sh \
sample_ahbe.conf
integration-test-common.sh \
small-integration-test.sh \
mergedir.sh \
sample_delcache.sh \
sample_ahbe.conf
testdir = test
noinst_PROGRAMS = \
junk_data \
write_multiblock \
mknod_test \
truncate_read_file \
cr_filename
junk_data_SOURCES = junk_data.cc
write_multiblock_SOURCES = write_multiblock.cc
mknod_test_SOURCES = mknod_test.cc
truncate_read_file_SOURCES = truncate_read_file.cc
cr_filename_SOURCES = cr_filename.cc
clang-tidy:
clang-tidy -extra-arg=-std=@CPP_VERSION@ \
$(junk_data_SOURCES) \
$(write_multiblock_SOURCES) \
$(mknod_test_SOURCES) \
$(truncate_read_file_SOURCES) \
$(cr_filename_SOURCES) \
-- $(DEPS_CFLAGS) $(CPPFLAGS)
#
# Local variables:
# tab-width: 4
# c-basic-offset: 4
# End:
# vim600: expandtab sw=4 ts=4 fdm=marker
# vim<600: expandtab sw=4 ts=4
#

View File

@ -0,0 +1,2 @@
com.bouncestorage.chaoshttpproxy.http_503=1
com.bouncestorage.chaoshttpproxy.success=9

63
test/compile_all_targets.sh Executable file
View File

@ -0,0 +1,63 @@
#!/bin/bash
#
# s3fs - FUSE-based file system backed by Amazon S3
#
# Copyright 2007-2008 Randy Rizun <rrizun@gmail.com>
#
# 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.
#
set -o errexit
set -o nounset
set -o pipefail
COMMON_FLAGS='-O -Wall -Werror'
make clean
CXXFLAGS="$COMMON_FLAGS" ./configure --with-gnutls
make --jobs "$(nproc)"
make clean
CXXFLAGS="$COMMON_FLAGS" ./configure --with-gnutls --with-nettle
make --jobs "$(nproc)"
make clean
CXXFLAGS="$COMMON_FLAGS" ./configure --with-nss
make --jobs "$(nproc)"
make clean
CXXFLAGS="$COMMON_FLAGS" ./configure --with-openssl
make --jobs "$(nproc)"
make clean
CXXFLAGS="$COMMON_FLAGS -std=c++23" ./configure
make --jobs "$(nproc)"
make clean
CXXFLAGS="$COMMON_FLAGS -m32" ./configure
make --jobs "$(nproc)"
make clean
CXX=clang++ CXXFLAGS="$COMMON_FLAGS -Wshorten-64-to-32" ./configure
make --jobs "$(nproc)"
#
# Local variables:
# tab-width: 4
# c-basic-offset: 4
# End:
# vim600: expandtab sw=4 ts=4 fdm=marker
# vim<600: expandtab sw=4 ts=4
#

77
test/cr_filename.cc Normal file
View File

@ -0,0 +1,77 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2021 Andrew Gaul <andrew@gaul.org>
*
* 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.
*/
#include <cstdio>
#include <cstdlib>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
// [NOTE]
// This is a program used for file size inspection.
// File size checking should be done by the caller of this program.
// This program truncates the file and reads the file in another process
// between truncate and flush(close file).
//
int main(int argc, const char *argv[])
{
if(argc != 2){
fprintf(stderr, "[ERROR] Wrong parameters\n");
fprintf(stdout, "[Usage] cr_filename <base file path>\n");
exit(EXIT_FAILURE);
}
int fd;
char filepath[4096];
snprintf(filepath, sizeof(filepath), "%s\r", argv[1]);
filepath[sizeof(filepath) - 1] = '\0'; // for safety
// create empty file
if(-1 == (fd = open(filepath, O_CREAT|O_RDWR, 0644))){
fprintf(stderr, "[ERROR] Could not open file(%s)\n", filepath);
exit(EXIT_FAILURE);
}
close(fd);
// stat
struct stat buf;
if(0 != stat(filepath, &buf)){
fprintf(stderr, "[ERROR] Could not get stat for file(%s)\n", filepath);
exit(EXIT_FAILURE);
}
// remove file
if(0 != unlink(filepath)){
fprintf(stderr, "[ERROR] Could not remove file(%s)\n", filepath);
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

143
test/filter-suite-log.sh Executable file
View File

@ -0,0 +1,143 @@
#!/bin/bash
#
# s3fs - FUSE-based file system backed by Amazon S3
#
# Copyright 2007-2008 Randy Rizun <rrizun@gmail.com>
#
# 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.
#
func_usage()
{
echo ""
echo "Usage: $1 [-h] <log file path>"
echo " -h print help"
echo " log file path path for test-suite.log"
echo ""
}
PRGNAME=$(basename "$0")
SCRIPTDIR=$(dirname "$0")
S3FSDIR=$(cd "${SCRIPTDIR}"/.. || exit 1; pwd)
TOPDIR=$(cd "${S3FSDIR}"/test || exit 1; pwd)
SUITELOG="${TOPDIR}/test-suite.log"
TMP_LINENO_FILE="/tmp/.lineno.tmp"
while [ $# -ne 0 ]; do
if [ "$1" = "" ]; then
break
elif [ "$1" = "-h" ] || [ "$1" = "-H" ] || [ "$1" = "--help" ] || [ "$1" = "--HELP" ]; then
func_usage "${PRGNAME}"
exit 0
else
SUITELOG=$1
fi
shift
done
if [ ! -f "${SUITELOG}" ]; then
echo "[ERROR] not found ${SUITELOG} log file."
exit 1
fi
#
# Extract keyword line numbers and types
#
# 0 : normal line
# 1 : start line for one small test(specified in integration-test-main.sh)
# 2 : passed line of end of one small test(specified in test-utils.sh)
# 3 : failed line of end of one small test(specified in test-utils.sh)
#
grep -n -e 'test_.*: ".*"' -o -e 'test_.* passed' -o -e 'test_.* failed' "${SUITELOG}" 2>/dev/null | sed 's/:test_.*: ".*"/ 1/g' | sed 's/:test_.* passed/ 2/g' | sed 's/:test_.* failed/ 3/g' > "${TMP_LINENO_FILE}"
#
# Loop for printing result
#
prev_line_type=0
prev_line_number=1
while read -r line; do
# line is "<line number> <line type>"
#
# shellcheck disable=SC2206
number_type=(${line})
head_line_cnt=$((number_type[0] - 1))
tail_line_cnt=$((number_type[0] - prev_line_number))
if [ "${number_type[1]}" -eq 2 ]; then
echo ""
fi
if [ "${prev_line_type}" -eq 1 ]; then
if [ "${number_type[1]}" -eq 2 ]; then
# if passed, cut s3fs information messages
head "-${head_line_cnt}" "${SUITELOG}" | tail "-${tail_line_cnt}" | grep -v -e '[0-9]\+%' | grep -v -e '^s3fs: ' -a -e '\[INF\]'
elif [ "${number_type[1]}" -eq 3 ]; then
# if failed, print all
head "-${head_line_cnt}" "${SUITELOG}" | tail "-${tail_line_cnt}" | grep -v -e '[0-9]\+%'
else
# there is start keyword but not end keyword, so print all
head "-${head_line_cnt}" "${SUITELOG}" | tail "-${tail_line_cnt}" | grep -v -e '[0-9]\+%'
fi
elif [ "${prev_line_type}" -eq 2 ] || [ "${prev_line_type}" -eq 3 ]; then
if [ "${number_type[1]}" -eq 2 ] || [ "${number_type[1]}" -eq 3 ]; then
# previous is end of chmpx, but this type is end of chmpx without start keyword. then print all
head "-${head_line_cnt}" "${SUITELOG}" | tail "-${tail_line_cnt}" | grep -v -e '[0-9]\+%'
else
# this area is not from start to end, cut s3fs information messages
head "-${head_line_cnt}" "${SUITELOG}" | tail "-${tail_line_cnt}" | grep -v -e '[0-9]\+%' | grep -v -e '^s3fs: ' -a -e '\[INF\]'
fi
else
if [ "${number_type[1]}" -eq 2 ] || [ "${number_type[1]}" -eq 3 ]; then
# previous is normal, but this type is end of chmpx without start keyword. then print all
head "-${head_line_cnt}" "${SUITELOG}" | tail "-${tail_line_cnt}" | grep -v -e '[0-9]\+%'
else
# this area is normal, cut s3fs information messages
head "-${head_line_cnt}" "${SUITELOG}" | tail "-${tail_line_cnt}" | grep -v -e '[0-9]\+%' | grep -v -e '^s3fs: ' -a -e '\[INF\]'
fi
fi
if [ "${number_type[1]}" -eq 3 ]; then
echo ""
fi
prev_line_type="${number_type[1]}"
prev_line_number="${number_type[0]}"
done < "${TMP_LINENO_FILE}"
#
# Print rest lines
#
file_line_cnt=$(wc -l < "${SUITELOG}")
tail_line_cnt=$((file_line_cnt - prev_line_number))
if [ "${prev_line_type}" -eq 1 ]; then
tail "-${tail_line_cnt}" "${SUITELOG}" | grep -v -e '[0-9]\+%'
else
tail "-${tail_line_cnt}" "${SUITELOG}" | grep -v -e '[0-9]\+%' | grep -v -e '^s3fs: ' -a -e '\[INF\]'
fi
#
# Remove temp file
#
rm -f "${TMP_LINENO_FILE}"
exit 0
#
# Local variables:
# tab-width: 4
# c-basic-offset: 4
# End:
# vim600: expandtab sw=4 ts=4 fdm=marker
# vim<600: expandtab sw=4 ts=4
#

View File

@ -1,4 +1,23 @@
#!/bin/bash
#
# s3fs - FUSE-based file system backed by Amazon S3
#
# Copyright 2007-2008 Randy Rizun <rrizun@gmail.com>
#
# 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.
#
#
# Common code for starting an s3fs-fuse mountpoint and an S3Proxy instance
@ -8,13 +27,19 @@
# environment variables:
#
# S3FS_CREDENTIALS_FILE=keyfile s3fs format key file
# S3FS_PROFILE=name s3fs profile to use (overrides key file)
# TEST_BUCKET_1=bucketname Name of bucket to use
# S3PROXY_BINARY="" Specify empty string to skip S3Proxy start
# S3_URL="http://s3.amazonaws.com" Specify Amazon AWS as the S3 provider
# S3_URL="https://s3.amazonaws.com" Specify Amazon AWS as the S3 provider
# S3_ENDPOINT="us-east-1" Specify region
# TMPDIR="/var/tmp" Set to use a temporary directory different
# from /var/tmp
# CHAOS_HTTP_PROXY=1 Test proxy(environment) by CHAOS HTTP PROXY
# CHAOS_HTTP_PROXY_OPT=1 Test proxy(option) by CHAOS HTTP PROXY
#
# Example of running against Amazon S3 using a bucket named "bucket:
# Example of running against Amazon S3 using a bucket named "bucket":
#
# S3FS_CREDENTIALS_FILE=keyfile TEST_BUCKET_1=bucket S3PROXY_BINARY="" S3_URL="http://s3.amazonaws.com" ./small-integration-test.sh
# S3FS_CREDENTIALS_FILE=keyfile TEST_BUCKET_1=bucket S3PROXY_BINARY="" S3_URL="https://s3.amazonaws.com" ./small-integration-test.sh
#
# To change the s3fs-fuse debug level:
#
@ -27,7 +52,7 @@
#
# Run all of the tests from the makefile
#
# S3FS_CREDENTIALS_FILE=keyfile TEST_BUCKET_1=bucket S3PROXY_BINARY="" S3_URL="http://s3.amazonaws.com" make check
# S3FS_CREDENTIALS_FILE=keyfile TEST_BUCKET_1=bucket S3PROXY_BINARY="" S3_URL="https://s3.amazonaws.com" make check
#
# Run the tests with request auth turned off in both S3Proxy and s3fs-fuse. This can be
# useful for poking around with plain old curl
@ -38,55 +63,93 @@
# eg: VALGRIND="--tool=memcheck --leak-check=full" ./small-integration-test.sh
set -o errexit
set -o pipefail
S3FS=../src/s3fs
# Allow these defaulted values to be overridden
: ${S3_URL:="http://127.0.0.1:8080"}
: ${S3FS_CREDENTIALS_FILE:="passwd-s3fs"}
: ${TEST_BUCKET_1:="s3fs-integration-test"}
#
# [NOTE]
# CHAOS HTTP PROXY does not support HTTPS.
#
if [ -z "${CHAOS_HTTP_PROXY}" ] && [ -z "${CHAOS_HTTP_PROXY_OPT}" ]; then
: "${S3_URL:="https://127.0.0.1:8080"}"
else
: "${S3_URL:="http://127.0.0.1:8080"}"
fi
: "${S3_ENDPOINT:="us-east-1"}"
: "${S3FS_CREDENTIALS_FILE:="passwd-s3fs"}"
: "${TEST_BUCKET_1:="s3fs-integration-test"}"
export TEST_BUCKET_1
export S3_URL
export TEST_SCRIPT_DIR=`pwd`
export S3_ENDPOINT
export S3PROXY_CACERT_FILE
TEST_SCRIPT_DIR=$(pwd)
export TEST_SCRIPT_DIR
export TEST_BUCKET_MOUNT_POINT_1=${TEST_BUCKET_1}
S3PROXY_VERSION="1.4.0"
S3PROXY_BINARY=${S3PROXY_BINARY-"s3proxy-${S3PROXY_VERSION}"}
S3PROXY_VERSION="2.7.0"
S3PROXY_HASH="1a13c27f78902b57db871a2e638f520f439811b1c98b2208ff71ba64b61c4f3f"
S3PROXY_BINARY="${S3PROXY_BINARY-"s3proxy-${S3PROXY_VERSION}"}"
CHAOS_HTTP_PROXY_VERSION="1.1.0"
CHAOS_HTTP_PROXY_HASH="9ad1b9ac6569e99b2db3e7edfdd78fae0ea5c83069beccdf6bceebc848add2e7"
CHAOS_HTTP_PROXY_BINARY="chaos-http-proxy-${CHAOS_HTTP_PROXY_VERSION}"
PJDFSTEST_HASH="c711b5f6b666579846afba399a998f74f60c488b"
if [ ! -f "$S3FS_CREDENTIALS_FILE" ]
then
echo "Missing credentials file: $S3FS_CREDENTIALS_FILE"
echo "Missing credentials file: ${S3FS_CREDENTIALS_FILE}"
exit 1
fi
chmod 600 "$S3FS_CREDENTIALS_FILE"
chmod 600 "${S3FS_CREDENTIALS_FILE}"
if [ ! -d $TEST_BUCKET_MOUNT_POINT_1 ]
then
mkdir -p $TEST_BUCKET_MOUNT_POINT_1
if [ -z "${S3FS_PROFILE}" ]; then
AWS_ACCESS_KEY_ID=$(cut -d: -f1 "${S3FS_CREDENTIALS_FILE}")
export AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY=$(cut -d: -f2 "${S3FS_CREDENTIALS_FILE}")
export AWS_SECRET_ACCESS_KEY
fi
if [ ! -d "${TEST_BUCKET_MOUNT_POINT_1}" ]; then
mkdir -p "${TEST_BUCKET_MOUNT_POINT_1}"
fi
# [NOTE]
# For the Github Actions macos-14 Runner,
# Set variables for when stdbuf is used and when it is not.
#
if [ -n "${STDBUF_BIN}" ]; then
STDBUF_COMMAND_LINE=("${STDBUF_BIN}" -oL -eL)
else
STDBUF_COMMAND_LINE=()
fi
# This function execute the function parameters $1 times
# before giving up, with 1 second delays.
function retry {
set +o errexit
N=$1; shift;
status=0
for i in $(seq $N); do
echo "Trying: $@"
$@
status=$?
if [ $status == 0 ]; then
local N="$1"
shift
rc=0
for _ in $(seq "${N}"); do
echo "Trying: $*"
# shellcheck disable=SC2068,SC2294
eval $@
rc=$?
if [ "${rc}" -eq 0 ]; then
break
fi
sleep 1
echo "Retrying: $@"
echo "Retrying: $*"
done
if [ $status != 0 ]; then
echo "timeout waiting for $@"
if [ "${rc}" -ne 0 ]; then
echo "timeout waiting for $*"
fi
set -o errexit
return $status
return "${rc}"
}
# Proxy is not started if S3PROXY_BINARY is an empty string
@ -95,75 +158,160 @@ function retry {
#
function start_s3proxy {
if [ -n "${PUBLIC}" ]; then
S3PROXY_CONFIG="s3proxy-noauth.conf"
local S3PROXY_CONFIG="s3proxy-noauth.conf"
else
S3PROXY_CONFIG="s3proxy.conf"
if [ -z "${CHAOS_HTTP_PROXY}" ] && [ -z "${CHAOS_HTTP_PROXY_OPT}" ]; then
local S3PROXY_CONFIG="s3proxy.conf"
else
local S3PROXY_CONFIG="s3proxy_http.conf"
fi
fi
if [ -n "${S3PROXY_BINARY}" ]
then
if [ ! -e "${S3PROXY_BINARY}" ]; then
wget "https://github.com/andrewgaul/s3proxy/releases/download/s3proxy-${S3PROXY_VERSION}/s3proxy" \
--quiet -O "${S3PROXY_BINARY}"
curl "https://github.com/gaul/s3proxy/releases/download/s3proxy-${S3PROXY_VERSION}/s3proxy" \
--fail --location --silent --output "/tmp/${S3PROXY_BINARY}"
echo "$S3PROXY_HASH" "/tmp/${S3PROXY_BINARY}" | sha256sum --check
mv "/tmp/${S3PROXY_BINARY}" "${S3PROXY_BINARY}"
chmod +x "${S3PROXY_BINARY}"
fi
stdbuf -oL -eL java -jar "$S3PROXY_BINARY" --properties $S3PROXY_CONFIG | stdbuf -oL -eL sed -u "s/^/s3proxy: /" &
# generate self-signed SSL certificate
#
# [NOTE]
# The PROXY test is HTTP only, so do not create CA certificates.
#
if [ -z "${CHAOS_HTTP_PROXY}" ] && [ -z "${CHAOS_HTTP_PROXY_OPT}" ]; then
S3PROXY_CACERT_FILE="/tmp/keystore.pem"
rm -f /tmp/keystore.jks "${S3PROXY_CACERT_FILE}"
printf 'password\npassword\n\n\n\n\n\n\ny' | keytool -genkey -keystore /tmp/keystore.jks -keyalg RSA -keysize 2048 -validity 365 -ext SAN=IP:127.0.0.1
echo password | keytool -exportcert -keystore /tmp/keystore.jks -rfc -file "${S3PROXY_CACERT_FILE}"
else
S3PROXY_CACERT_FILE=""
fi
"${STDBUF_COMMAND_LINE[@]}" java -jar "${S3PROXY_BINARY}" --properties "${S3PROXY_CONFIG}" &
S3PROXY_PID=$!
# wait for S3Proxy to start
for i in $(seq 30);
do
if exec 3<>"/dev/tcp/127.0.0.1/8080";
then
exec 3<&- # Close for read
exec 3>&- # Close for write
break
fi
sleep 1
done
wait_for_port 8080
fi
S3PROXY_PID=$(netstat -lpnt | grep :8080 | awk '{ print $7 }' | sed -u 's|/java||')
if [ -n "${CHAOS_HTTP_PROXY}" ] || [ -n "${CHAOS_HTTP_PROXY_OPT}" ]; then
if [ ! -e "${CHAOS_HTTP_PROXY_BINARY}" ]; then
curl "https://github.com/bouncestorage/chaos-http-proxy/releases/download/chaos-http-proxy-${CHAOS_HTTP_PROXY_VERSION}/chaos-http-proxy" \
--fail --location --silent --output "/tmp/${CHAOS_HTTP_PROXY_BINARY}"
echo "$CHAOS_HTTP_PROXY_HASH" "/tmp/${CHAOS_HTTP_PROXY_BINARY}" | sha256sum --check
mv "/tmp/${CHAOS_HTTP_PROXY_BINARY}" "${CHAOS_HTTP_PROXY_BINARY}"
chmod +x "${CHAOS_HTTP_PROXY_BINARY}"
fi
"${STDBUF_COMMAND_LINE[@]}" java -jar "${CHAOS_HTTP_PROXY_BINARY}" --properties chaos-http-proxy.conf &
CHAOS_HTTP_PROXY_PID=$!
# wait for Chaos HTTP Proxy to start
wait_for_port 1080
fi
if [ ! -d "pjd-pjdfstest-${PJDFSTEST_HASH:0:7}" ]; then
curl "https://api.github.com/repos/pjd/pjdfstest/tarball/${PJDFSTEST_HASH}" \
--fail --location --silent --output /tmp/pjdfstest.tar.gz
tar zxf /tmp/pjdfstest.tar.gz
rm -f /tmp/pjdfstest.tar.gz
rm -f pjdfstest
ln -s "pjd-pjdfstest-${PJDFSTEST_HASH:0:7}" pjdfstest
(cd pjdfstest && autoreconf -ifs && ./configure && make)
fi
}
function stop_s3proxy {
if [ -n "${S3PROXY_PID}" ]
then
kill $S3PROXY_PID
wait $S3PROXY_PID
kill "${S3PROXY_PID}"
fi
if [ -n "${CHAOS_HTTP_PROXY_PID}" ]
then
kill "${CHAOS_HTTP_PROXY_PID}"
fi
}
# Mount the bucket, function arguments passed to s3fs in addition to
# a set of common arguments.
function start_s3fs {
# Public bucket if PUBLIC is set
if [ -n "${PUBLIC}" ]; then
AUTH_OPT="-o public_bucket=1"
local AUTH_OPT="-o public_bucket=1"
elif [ -n "${S3FS_PROFILE}" ]; then
local AUTH_OPT="-o profile=${S3FS_PROFILE}"
else
AUTH_OPT="-o passwd_file=${S3FS_CREDENTIALS_FILE}"
local AUTH_OPT="-o passwd_file=${S3FS_CREDENTIALS_FILE}"
fi
# If VALGRIND is set, pass it as options to valgrind.
# start valgrind-listener in another shell.
# eg: VALGRIND="--tool=memcheck --leak-check=full" ./small-integration-test.sh
# Start valgind-listener (default port is 1500)
# Start valgrind-listener (default port is 1500)
if [ -n "${VALGRIND}" ]; then
VALGRIND_EXEC="valgrind ${VALGRIND} --log-socket=127.0.1.1"
fi
# On OSX only, we need to specify the direct_io and auto_cache flag.
#
# And Turn off creation and reference of spotlight index.
# (Leaving spotlight ON will result in a lot of wasted requests,
# which will affect test execution time)
#
if [ "$(uname)" = "Darwin" ]; then
local DIRECT_IO_OPT="-o direct_io -o auto_cache"
# disable spotlight
sudo mdutil -a -i off
else
local DIRECT_IO_OPT=""
fi
# Set environment variables or options for proxy.
# And the PROXY test is HTTP only and does not set CA certificates.
#
if [ -n "${CHAOS_HTTP_PROXY}" ]; then
export http_proxy="127.0.0.1:1080"
S3FS_HTTP_PROXY_OPT=""
elif [ -n "${CHAOS_HTTP_PROXY_OPT}" ]; then
S3FS_HTTP_PROXY_OPT="-o proxy=http://127.0.0.1:1080"
else
S3FS_HTTP_PROXY_OPT=""
fi
# [NOTE]
# For macos fuse-t, we need to specify the "noattrcache" option to
# disable NFS caching.
#
if [ "$(uname)" = "Darwin" ]; then
local FUSE_T_ATTRCACHE_OPT="-o noattrcache"
else
local FUSE_T_ATTRCACHE_OPT=""
fi
# [NOTE]
# On macOS we may get a VERIFY error for the self-signed certificate used by s3proxy.
# We can specify NO_CHECK_CERT=1 to avoid this.
#
if [ -n "${NO_CHECK_CERT}" ] && [ "${NO_CHECK_CERT}" -eq 1 ]; then
local NO_CHECK_CERT_OPT="-o no_check_certificate"
else
local NO_CHECK_CERT_OPT=""
fi
# Common s3fs options:
#
# TODO: Allow all these options to be overriden with env variables
# TODO: Allow all these options to be overridden with env variables
#
# sigv2
# Historically because S3Proxy only supports sigv2.
# use_path_request_style
# The test env doesn't have virtual hosts
# createbucket
# S3Proxy always starts with no buckets, this tests the s3fs-fuse
# automatic bucket creation path.
# $AUTH_OPT
# Will be either "-o public_bucket=1"
# or
@ -175,28 +323,60 @@ function start_s3fs {
#
# subshell with set -x to log exact invocation of s3fs-fuse
# shellcheck disable=SC2086
(
set -x
stdbuf -oL -eL \
${VALGRIND_EXEC} ${S3FS} \
$TEST_BUCKET_1 \
$TEST_BUCKET_MOUNT_POINT_1 \
-o sigv2 \
CURL_CA_BUNDLE="${S3PROXY_CACERT_FILE}" \
"${STDBUF_COMMAND_LINE[@]}" \
${VALGRIND_EXEC} \
${S3FS} \
${TEST_BUCKET_1} \
${TEST_BUCKET_MOUNT_POINT_1} \
-o use_path_request_style \
-o url=${S3_URL} \
-o createbucket \
-o url="${S3_URL}" \
-o region="${S3_ENDPOINT}" \
-o use_xattr=1 \
-o enable_unsigned_payload \
${AUTH_OPT} \
-o dbglevel=${DBGLEVEL:=info} \
${DIRECT_IO_OPT} \
${S3FS_HTTP_PROXY_OPT} \
${NO_CHECK_CERT_OPT} \
${FUSE_T_ATTRCACHE_OPT} \
-o stat_cache_expire=1 \
-o stat_cache_interval_expire=1 \
-o dbglevel="${DBGLEVEL:=info}" \
-o no_time_stamp_msg \
-o retries=3 \
-f \
${@} \
|& stdbuf -oL -eL sed -u "s/^/s3fs: /" &
)
"${@}" &
echo $! >&3
) 3>pid | "${STDBUF_COMMAND_LINE[@]}" "${SED_BIN}" "${SED_BUFFER_FLAG}" "s/^/s3fs: /" &
sleep 1
S3FS_PID=$(<pid)
export S3FS_PID
rm -f pid
retry 5 grep -q $TEST_BUCKET_MOUNT_POINT_1 /proc/mounts || exit 1
if [ "$(uname)" = "Darwin" ]; then
local TRYCOUNT=0
while [ "${TRYCOUNT}" -le "${RETRIES:=20}" ]; do
_DF_RESULT=$(df 2>/dev/null)
if echo "${_DF_RESULT}" | grep -q "${TEST_BUCKET_MOUNT_POINT_1}"; then
break;
fi
sleep 1
TRYCOUNT=$((TRYCOUNT + 1))
done
if [ "${TRYCOUNT}" -gt "${RETRIES}" ]; then
echo "Waited ${TRYCOUNT} seconds, but it could not be mounted."
exit 1
fi
else
retry "${RETRIES:=20}" grep -q "${TEST_BUCKET_MOUNT_POINT_1}" /proc/mounts || exit 1
fi
# Quick way to start system up for manual testing with options under test
if [[ -n ${INTERACT} ]]; then
echo "Mountpoint $TEST_BUCKET_MOUNT_POINT_1 is ready"
if [[ -n "${INTERACT}" ]]; then
echo "Mountpoint ${TEST_BUCKET_MOUNT_POINT_1} is ready"
echo "control-C to quit"
sleep infinity
exit 0
@ -205,14 +385,29 @@ function start_s3fs {
function stop_s3fs {
# Retry in case file system is in use
if grep -q $TEST_BUCKET_MOUNT_POINT_1 /proc/mounts; then
retry 10 grep -q $TEST_BUCKET_MOUNT_POINT_1 /proc/mounts && fusermount -u $TEST_BUCKET_MOUNT_POINT_1
if [ "$(uname)" = "Darwin" ]; then
if df | grep -q "${TEST_BUCKET_MOUNT_POINT_1}"; then
retry 10 df "|" grep -q "${TEST_BUCKET_MOUNT_POINT_1}" "&&" umount "${TEST_BUCKET_MOUNT_POINT_1}"
fi
else
if grep -q "${TEST_BUCKET_MOUNT_POINT_1}" /proc/mounts; then
retry 10 grep -q "${TEST_BUCKET_MOUNT_POINT_1}" /proc/mounts "&&" fusermount -u "${TEST_BUCKET_MOUNT_POINT_1}"
fi
fi
}
# trap handlers do not stack. If a test sets its own, the new handler should call common_exit_handler
function common_exit_handler {
stop_s3proxy
stop_s3fs
stop_s3proxy
}
trap common_exit_handler EXIT
#
# Local variables:
# tab-width: 4
# c-basic-offset: 4
# End:
# vim600: expandtab sw=4 ts=4 fdm=marker
# vim<600: expandtab sw=4 ts=4
#

File diff suppressed because it is too large Load Diff

50
test/junk_data.cc Normal file
View File

@ -0,0 +1,50 @@
/*
* s3fs - FUSE-based file system backed by Amazon S3
*
* Copyright(C) 2021 Andrew Gaul <andrew@gaul.org>
*
* 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.
*/
// Generate junk data at high speed. An alternative to dd if=/dev/urandom.
#include <cstdint>
#include <cstdio>
#include <cstdlib>
int main(int argc, const char *argv[])
{
if (argc != 2) {
return 1;
}
uint64_t count = strtoull(argv[1], nullptr, 10);
char buf[128 * 1024];
for (uint64_t i = 0; i < count; i += sizeof(buf)) {
for (uint64_t j = 0; j < sizeof(buf) / sizeof(i); ++j) {
*(reinterpret_cast<uint64_t *>(buf) + j) = i / sizeof(i) + j;
}
fwrite(buf, 1, sizeof(buf) > count - i ? count - i : sizeof(buf), stdout);
}
return 0;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: expandtab sw=4 ts=4 fdm=marker
* vim<600: expandtab sw=4 ts=4
*/

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