diff options
Diffstat (limited to 'zen')
-rw-r--r-- | zen/file_access.cpp | 3 | ||||
-rw-r--r-- | zen/legacy_compiler.h | 2 | ||||
-rw-r--r-- | zen/open_ssl.cpp | 16 | ||||
-rw-r--r-- | zen/open_ssl.h | 2 | ||||
-rw-r--r-- | zen/resolve_path.cpp | 6 | ||||
-rw-r--r-- | zen/serialize.h | 5 | ||||
-rw-r--r-- | zen/string_base.h | 72 | ||||
-rw-r--r-- | zen/sys_info.cpp | 2 |
8 files changed, 67 insertions, 41 deletions
diff --git a/zen/file_access.cpp b/zen/file_access.cpp index 01dda68c..0c28f325 100644 --- a/zen/file_access.cpp +++ b/zen/file_access.cpp @@ -200,6 +200,9 @@ void zen::removeDirectoryPlain(const Zstring& dirPath) //throw FileError THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtPath(dirPath)), "unlink"); return; } + //if (ec == ERROR_SHARING_VIOLATION) => getLockingProcesses() can't handle directory paths! :( RmGetList() fails with ERROR_ACCESS_DENIED + //https://blog.yaakov.online/failed-experiment-what-processes-have-a-lock-on-this-folder/ + throw FileError(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtPath(dirPath)), formatSystemError(functionName, ec)); } /* Windows: may spuriously fail with ERROR_DIR_NOT_EMPTY(145) even though all child items have diff --git a/zen/legacy_compiler.h b/zen/legacy_compiler.h index 8f93153e..8606f95c 100644 --- a/zen/legacy_compiler.h +++ b/zen/legacy_compiler.h @@ -35,7 +35,7 @@ basic_string<Char, Traits, Alloc> operator+(basic_string<Char, Traits, Alloc>&& //template <class Char> inline //basic_string<Char> operator+(const basic_string<Char>& lhs, const basic_string_view<Char>& rhs) { return basic_string<Char>(lhs) + rhs; } -//-> somewhat inefficient: enable + optimize when needed +//-> somewhat inefficient: single memory allocation should suffice!!! } //--------------------------------------------------------------------------------- diff --git a/zen/open_ssl.cpp b/zen/open_ssl.cpp index 1f556656..9278b6dd 100644 --- a/zen/open_ssl.cpp +++ b/zen/open_ssl.cpp @@ -151,7 +151,13 @@ std::shared_ptr<EVP_PKEY> streamToKey(const std::string& keyStream, RsaStreamTyp throw SysError(formatLastOpenSSLError("OSSL_DECODER_CTX_new_for_pkey")); ZEN_ON_SCOPE_EXIT(::OSSL_DECODER_CTX_free(decCtx)); - //key stream is password-protected? => OSSL_DECODER_CTX_set_passphrase() +#if 0 //key stream is password-protected? => OSSL_DECODER_CTX_set_passphrase() + if (!password.empty()) + if (::OSSL_DECODER_CTX_set_passphrase(decCtx, //OSSL_DECODER_CTX *ctx + reinterpret_cast<const unsigned char*>(password.c_str()), //const unsigned char* kstr + password.size()) != 1) //size_t klen + throw SysError(formatLastOpenSSLError("OSSL_DECODER_CTX_set_passphrase")); +#endif const unsigned char* keyBuf = reinterpret_cast<const unsigned char*>(keyStream.c_str()); size_t keyLen = keyStream.size(); @@ -409,11 +415,9 @@ void zen::verifySignature(const std::string& message, const std::string& signatu } -bool zen::isPuttyKeyStream(const std::string& keyStream) +bool zen::isPuttyKeyStream(const std::string_view keyStream) { - std::string firstLine(keyStream.begin(), std::find_if(keyStream.begin(), keyStream.end(), isLineBreak<char>)); - trim(firstLine); - return startsWith(firstLine, "PuTTY-User-Key-File-2:"); + return startsWith(trimCpy(keyStream, true, false), "PuTTY-User-Key-File-"); } @@ -548,7 +552,7 @@ std::string zen::convertPuttyKeyToPkix(const std::string& keyStream, const std:: auto numToBeString = [](size_t n) -> std::string { - static_assert(std::endian::native == std::endian::little && sizeof(n) >= 4); + static_assert(std::endian::native == std::endian::little&& sizeof(n) >= 4); const char* numStr = reinterpret_cast<const char*>(&n); return {numStr[3], numStr[2], numStr[1], numStr[0]}; //big endian! }; diff --git a/zen/open_ssl.h b/zen/open_ssl.h index c66ad9c0..1a28f068 100644 --- a/zen/open_ssl.h +++ b/zen/open_ssl.h @@ -33,7 +33,7 @@ void verifySignature(const std::string& message, std::string convertRsaKey(const std::string& keyStream, RsaStreamType typeFrom, RsaStreamType typeTo, bool publicKey); //throw SysError -bool isPuttyKeyStream(const std::string& keyStream); +bool isPuttyKeyStream(const std::string_view keyStream); std::string convertPuttyKeyToPkix(const std::string& keyStream, const std::string& passphrase); //throw SysError } diff --git a/zen/resolve_path.cpp b/zen/resolve_path.cpp index 99e2f6c6..8b81e184 100644 --- a/zen/resolve_path.cpp +++ b/zen/resolve_path.cpp @@ -179,7 +179,7 @@ namespace //expand volume name if possible, return original input otherwise -Zstring expandVolumeName(Zstring pathPhrase) // [volname]:\folder [volname]\folder [volname]folder -> C:\folder +Zstring tryExpandVolumeName(Zstring pathPhrase) // [volname]:\folder [volname]\folder [volname]folder -> C:\folder { //we only expect the [.*] pattern at the beginning => do not touch dir names like "C:\somedir\[stuff]" trim(pathPhrase, true, false); @@ -205,7 +205,7 @@ std::vector<Zstring> zen::getPathPhraseAliases(const Zstring& itemPath) { //should use a replaceCpy() that considers "local path" case-sensitivity (if only we had one...) if (contains(itemPath, macroPath)) - pathAliases.push_back(makePathPhrase(replaceCpyAsciiNoCase(itemPath, macroPath, MACRO_SEP + Zstring(macroName) + MACRO_SEP))); + pathAliases.push_back(makePathPhrase(replaceCpyAsciiNoCase(itemPath, macroPath, Zstring() + MACRO_SEP + macroName + MACRO_SEP))); }; for (const Zchar* envName : @@ -242,7 +242,7 @@ Zstring zen::getResolvedFilePath(const Zstring& pathPhrase) //noexcept trim(path); //remove leading/trailing whitespace before allowing misinterpretation in applyLongPathPrefix() { - path = expandVolumeName(path); //may block for slow USB sticks and idle HDDs! + path = tryExpandVolumeName(path); //may block for slow USB sticks and idle HDDs! /* need to resolve relative paths: WINDOWS: diff --git a/zen/serialize.h b/zen/serialize.h index dd393422..a996b118 100644 --- a/zen/serialize.h +++ b/zen/serialize.h @@ -301,15 +301,16 @@ void unbufferedStreamCopy(Function1 tryRead /*(void* buffer, size_t bytesToRead) Function2 tryWrite /*(const void* buffer, size_t bytesToWrite) throw X; may return short*/, size_t blockSizeOut) //throw X { - /* caveat: buffer block sizes might not be power of 2: + /* caveat: buffer block sizes might not be a power of 2: - f_iosize for network share on macOS - libssh2 uses weird packet sizes like MAX_SFTP_OUTGOING_SIZE (30000), and will send incomplete packages if block size is not an exact multiple :( + - MTP uses file size as blocksize if under 256 kB (=> can be as small as 1 byte! https://freefilesync.org/forum/viewtopic.php?t=9823) => that's a problem because we want input/output sizes to be multiples of each other to help avoid the std::memmove() below */ #if 0 blockSizeIn = std::bit_ceil(blockSizeIn); blockSizeOut = std::bit_ceil(blockSizeOut); #endif - if (blockSizeIn <= 1 || blockSizeOut <= 1) + if (blockSizeIn == 0 || blockSizeOut == 0) throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__)); const size_t bufCapacity = blockSizeOut - 1 + blockSizeIn; diff --git a/zen/string_base.h b/zen/string_base.h index 3ebf848a..676d7f7f 100644 --- a/zen/string_base.h +++ b/zen/string_base.h @@ -61,11 +61,11 @@ protected: ~StorageDeepCopy() {} Char* create(size_t size) { return create(size, size); } - Char* create(size_t size, size_t capacity) + Char* create(size_t size, size_t minCapacity) { - assert(size <= capacity); - const size_t newCapacity = AP::calcCapacity(capacity); - assert(newCapacity >= capacity); + assert(size <= minCapacity); + const size_t newCapacity = AP::calcCapacity(minCapacity); + assert(newCapacity >= minCapacity); Descriptor* const newDescr = static_cast<Descriptor*>(this->allocate(sizeof(Descriptor) + (newCapacity + 1) * sizeof(Char))); //throw std::bad_alloc new (newDescr) Descriptor(size, newCapacity); @@ -124,18 +124,18 @@ protected: ~StorageRefCountThreadSafe() {} Char* create(size_t size) { return create(size, size); } - Char* create(size_t size, size_t capacity) + Char* create(size_t size, size_t minCapacity) { - assert(size <= capacity); + assert(size <= minCapacity); - if (capacity == 0) //perf: avoid memory allocation for empty string + if (minCapacity == 0) //perf: avoid memory allocation for empty string { ++globalEmptyString.descr.refCount; return &globalEmptyString.nullTerm; } - const size_t newCapacity = AP::calcCapacity(capacity); - assert(newCapacity >= capacity); + const size_t newCapacity = AP::calcCapacity(minCapacity); + assert(newCapacity >= minCapacity); Descriptor* const newDescr = static_cast<Descriptor*>(this->allocate(sizeof(Descriptor) + (newCapacity + 1) * sizeof(Char))); //throw std::bad_alloc new (newDescr) Descriptor(size, newCapacity); @@ -230,8 +230,8 @@ public: Zbase(const Char* str, size_t len) : Zbase(str, str + len) {} explicit Zbase(const std::basic_string_view<Char> view) : Zbase(view.begin(), view.end()) {} Zbase(size_t count, Char fillChar); - template <class InputIterator> - Zbase(InputIterator first, InputIterator last); + template <class RandomAccessIterator> + Zbase(RandomAccessIterator first, RandomAccessIterator last); Zbase(const Zbase& str); Zbase(Zbase&& tmp) noexcept; //explicit Zbase(Char ch); //dangerous if implicit: Char buffer[]; return buffer[0]; ups... forgot &, but not a compiler error! //-> non-standard extension!!! @@ -241,7 +241,7 @@ public: //operator const Char* () const; //NO implicit conversion to a C-string!! Many problems... one of them: if we forget to provide operator overloads, it'll just work with a Char*... operator std::basic_string_view<Char>() const& noexcept { return {data(), size()}; } - operator std::basic_string_view<Char>() const&& = delete; //=> probably a bug! + //operator std::basic_string_view<Char>() const&& = delete; //=> probably a bug! //STL accessors using iterator = Char*; @@ -281,8 +281,8 @@ public: Zbase& assign(const Char* str, size_t len) { return assign(str, str + len); } Zbase& append(const Char* str, size_t len) { return append(str, str + len); } - template <class InputIterator> Zbase& assign(InputIterator first, InputIterator last); - template <class InputIterator> Zbase& append(InputIterator first, InputIterator last); + template <class RandomAccessIterator> Zbase& assign(RandomAccessIterator first, RandomAccessIterator last); + template <class RandomAccessIterator> Zbase& append(RandomAccessIterator first, RandomAccessIterator last); void resize(size_t newSize, Char fillChar = 0); void swap(Zbase& str) { std::swap(rawStr_, str.rawStr_); } @@ -296,21 +296,31 @@ public: Zbase& operator+=(const Zbase& str) { return append(str.c_str(), str.size()); } Zbase& operator+=(const Char* str) { return append(str, strLength(str)); } Zbase& operator+=(Char ch) { return append(&ch, 1); } + Zbase& operator+=(const std::basic_string_view<Char> str) { return append(str.begin(), str.end()); } static const size_t npos = static_cast<size_t>(-1); + inline friend Zbase operator+( const Char* lhs, const Zbase& rhs) { return Zbase(lhs, strLength(lhs), rhs.c_str(), rhs.size()); } + inline friend Zbase operator+( Char lhs, const Zbase& rhs) { return Zbase(&lhs, 1, rhs.c_str(), rhs.size()); } + inline friend Zbase operator+(const std::basic_string_view<Char> lhs, const Zbase& rhs) { return Zbase(lhs.data(), lhs.size(), rhs.c_str(), rhs.size()); } + private: Zbase (int) = delete; // Zbase(size_t count, int) = delete; // Zbase& operator= (int) = delete; //detect usage errors by creating an intentional ambiguity with "Char" Zbase& operator+= (int) = delete; // void push_back (int) = delete; // + Zbase (std::nullptr_t) = delete; Zbase(size_t count, std::nullptr_t) = delete; Zbase& operator= (std::nullptr_t) = delete; Zbase& operator+= (std::nullptr_t) = delete; void push_back (std::nullptr_t) = delete; + //not part of std::string API => private: + Zbase(const Char* str1, size_t len1, const Char* str2, size_t len2); + //alternative: Zbase() + reserve() + 2 x append() + Char* rawStr_; }; @@ -328,14 +338,13 @@ template <class Char, template <class> class SP> std::strong_ordering operator<= template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(const Zbase<Char, SP>& lhs, const Zbase<Char, SP>& rhs) { return Zbase<Char, SP>(lhs) += rhs; } template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(const Zbase<Char, SP>& lhs, const Char* rhs) { return Zbase<Char, SP>(lhs) += rhs; } template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(const Zbase<Char, SP>& lhs, Char rhs) { return Zbase<Char, SP>(lhs) += rhs; } +template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(const Zbase<Char, SP>& lhs, const std::basic_string_view<Char> rhs) { return Zbase<Char, SP>(lhs) += rhs; } //don't use unified first argument but save one move-construction in the r-value case instead! template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(Zbase<Char, SP>&& lhs, const Zbase<Char, SP>& rhs) { return std::move(lhs += rhs); } //the move *is* needed!!! template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(Zbase<Char, SP>&& lhs, const Char* rhs) { return std::move(lhs += rhs); } //lhs, is an l-value parameter... template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(Zbase<Char, SP>&& lhs, Char rhs) { return std::move(lhs += rhs); } //and not a local variable => no copy elision - -template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(const Char* lhs, const Zbase<Char, SP>& rhs) { return Zbase<Char, SP>(lhs ) += rhs; } -template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+( Char lhs, const Zbase<Char, SP>& rhs) { return Zbase<Char, SP>(&lhs, 1) += rhs; } +template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(Zbase<Char, SP>&& lhs, const std::basic_string_view<Char> rhs) { return std::move(lhs += rhs); } template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(const Zbase<Char, SP>&, int) = delete; //detect usage errors template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(int, const Zbase<Char, SP>&) = delete; // @@ -359,8 +368,8 @@ Zbase<Char, SP>::Zbase() template <class Char, template <class> class SP> -template <class InputIterator> inline -Zbase<Char, SP>::Zbase(InputIterator first, InputIterator last) +template <class RandomAccessIterator> inline +Zbase<Char, SP>::Zbase(RandomAccessIterator first, RandomAccessIterator last) { rawStr_ = this->create(last - first); *std::copy(first, last, rawStr_) = 0; @@ -393,6 +402,15 @@ Zbase<Char, SP>::Zbase(Zbase<Char, SP>&& tmp) noexcept template <class Char, template <class> class SP> inline +Zbase<Char, SP>::Zbase(const Char* str1, size_t len1, const Char* str2, size_t len2) +{ + rawStr_ = this->create(len1 + len2); + std::copy (str1, str1 + len1, rawStr_); + *std::copy(str2, str2 + len2, rawStr_ + len1) = 0; +} + + +template <class Char, template <class> class SP> inline Zbase<Char, SP>::~Zbase() { static_assert(noexcept(this->~Zbase())); //has exception spec of compiler-generated destructor by default @@ -568,7 +586,7 @@ void Zbase<Char, SP>::reserve(size_t minCapacity) //make unshared and check capa //allocate a new string const size_t len = size(); Char* newStr = this->create(len, std::max(len, minCapacity)); //reserve() must NEVER shrink the string: logical const! - std::copy(rawStr_, rawStr_ + len + 1 /*0-termination*/, newStr); + *std::copy(rawStr_, rawStr_ + len , newStr) = 0; this->destroy(rawStr_); rawStr_ = newStr; @@ -577,10 +595,10 @@ void Zbase<Char, SP>::reserve(size_t minCapacity) //make unshared and check capa template <class Char, template <class> class SP> -template <class InputIterator> inline -Zbase<Char, SP>& Zbase<Char, SP>::assign(InputIterator first, InputIterator last) +template <class RandomAccessIterator> inline +Zbase<Char, SP>& Zbase<Char, SP>::assign(RandomAccessIterator first, RandomAccessIterator last) { - const size_t len = std::distance(first, last); + const size_t len = last - first; if (this->canWrite(rawStr_, len)) { *std::copy(first, last, rawStr_) = 0; @@ -594,10 +612,10 @@ Zbase<Char, SP>& Zbase<Char, SP>::assign(InputIterator first, InputIterator last template <class Char, template <class> class SP> -template <class InputIterator> inline -Zbase<Char, SP>& Zbase<Char, SP>::append(InputIterator first, InputIterator last) +template <class RandomAccessIterator> inline +Zbase<Char, SP>& Zbase<Char, SP>::append(RandomAccessIterator first, RandomAccessIterator last) { - const size_t len = std::distance(first, last); + const size_t len = last - first; //std::distance(first, last); if (len > 0) //avoid making this string unshared for no reason { const size_t thisLen = size(); @@ -622,7 +640,7 @@ Zbase<Char, SP>& Zbase<Char, SP>::operator=(const Zbase<Char, SP>& str) template <class Char, template <class> class SP> inline Zbase<Char, SP>& Zbase<Char, SP>::operator=(Zbase<Char, SP>&& tmp) noexcept { - //don't use swap() but end rawStr_ life time immediately + //don't swap() but end rawStr_ life time immediately this->destroy(rawStr_); rawStr_ = std::exchange(tmp.rawStr_, nullptr); diff --git a/zen/sys_info.cpp b/zen/sys_info.cpp index 5a044c3a..df0e4612 100644 --- a/zen/sys_info.cpp +++ b/zen/sys_info.cpp @@ -225,7 +225,7 @@ Zstring zen::getUserHome() //throw FileError return homePath; //root(0) => consider as request for elevation, NOT impersonation! - //=> no support for HOME variable :( + //=> "HOME=/root" :( const Zstring loginUser = getLoginUser(); //throw FileError |