From 983420cc8f6a139f127fbaf6199c725de2436d49 Mon Sep 17 00:00:00 2001 From: Tank Tang Date: Wed, 20 Feb 2019 16:46:32 +0800 Subject: [PATCH] Added support for Windows --- .gitignore | 4 + CMakeLists.txt | 146 ++++++++++++++++++-- CMakeSettings.json | 212 ++++++++++++++++++++++++++++- README.md | 128 +++++++++++++++-- include/hash.h | 51 +------ include/http/libcurl_http_client.h | 5 + include/logging.h | 98 +++++++++++++ include/retry.h | 5 + include/storage_EXPORTS.h | 2 +- include/utility.h | 6 + src/blob/blob_client.cpp | 6 + src/blob/blob_client_wrapper.cpp | 78 +++++------ src/hash.cpp | 53 +------- src/logging.cpp | 26 ++++ src/storage_credential.cpp | 4 - src/utility.cpp | 43 +++++- test/test_base.cpp | 138 +++++++++---------- test/test_base.h | 14 +- 18 files changed, 762 insertions(+), 257 deletions(-) create mode 100644 include/logging.h create mode 100644 src/logging.cpp diff --git a/.gitignore b/.gitignore index 1935e46..cf89b0b 100644 --- a/.gitignore +++ b/.gitignore @@ -52,9 +52,13 @@ dkms.conf # Cmake build +build.release # VS folder .vs/ +# Git +*.orig + # Test framework test/catch2 \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 88e321a..a73768a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,7 @@ option(BUILD_SAMPLES "Build sample codes" OFF) set(AZURE_STORAGE_LITE_HEADER include/storage_EXPORTS.h + include/logging.h include/base64.h include/common.h include/constants.h @@ -71,6 +72,7 @@ set(AZURE_STORAGE_LITE_HEADER ) set(AZURE_STORAGE_LITE_SOURCE + src/logging.cpp src/base64.cpp src/constants.cpp src/hash.cpp @@ -106,26 +108,138 @@ set(AZURE_STORAGE_LITE_SOURCE src/blob/blob_client_wrapper.cpp ) -find_package(CURL REQUIRED) -option(USE_OPENSSL "Use OpenSSL instead of GnuTLS" OFF) -find_package(Threads REQUIRED) -pkg_search_module(UUID REQUIRED uuid) -if (NOT ${USE_OPENSSL}) - find_package(GnuTLS REQUIRED) - set(EXTRA_INCLUDE ${GNUTLS_INCLUDE_DIR}) - set(EXTRA_LIBRARIES ${GNUTLS_LIBRARIES}) +if (UNIX) + option(USE_OPENSSL "Use OpenSSL instead of GnuTLS" OFF) + find_package(Threads REQUIRED) + find_package(CURL REQUIRED) + pkg_search_module(UUID REQUIRED uuid) + if (NOT ${USE_OPENSSL}) + find_package(GnuTLS REQUIRED) + set(EXTRA_INCLUDE ${GNUTLS_INCLUDE_DIR}) + set(EXTRA_LIBRARIES ${GNUTLS_LIBRARIES}) + include_directories(${PROJECT_SOURCE_DIR}/include ${CURL_INCLUDE_DIRS} ${UUID_INCLUDE_DIR} ${EXTRA_INCLUDE}) + else() + add_definitions(-DUSE_OPENSSL) + find_package(OpenSSL REQUIRED) + include_directories(${PROJECT_SOURCE_DIR}/include ${CURL_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${UUID_INCLUDE_DIR} ${EXTRA_INCLUDE}) + endif() else() + # Add the parameter/definition specifically for Windows. + option(USE_OPENSSL "Use OpenSSL instead of GnuTLS" ON) + option(CMAKE_BUILD_TYPE "The default build type" "Debug") + option(CMAKE_GENERATOR_PLATFORM "The Generator platform used for CMake" "x86") + #Construct the libcurl folder path + #This is because the cmake's FindCurl.cmake not being compatible with libcurl's buildscript on Windows. + #e.g. libcurl-vc15-x64-debug-static-ssl-static-ipv6-sspi + if((DEFINED CURL_ROOT_DIR) AND (NOT (CURL_ROOT_DIR STREQUAL ""))) + if(CMAKE_CL_64) + set(INHERIT_ENV "x64") + else() + set(INHERIT_ENV "x86") + endif() + + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(LIBRARY_BUILD_TYPE "debug") + else() + set(LIBRARY_BUILD_TYPE "release") + endif() + + if(CURL_LINK_TYPE STREQUAL "static") + add_definitions(-DCURL_STATICLIB) + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CURL_LIBRARY_NAME "lib\\libcurl_a_debug.lib") + else() + set(CURL_LIBRARY_NAME "lib\\libcurl_a.lib") + endif() + else() + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CURL_LIBRARY_NAME "bin\\libcurl_debug.dll") + else() + set(CURL_LIBRARY_NAME "bin\\libcurl.dll") + endif() + endif() + + set(CURL_LIBRARIES "${CURL_ROOT_DIR}\\builds\\libcurl-vc15-${INHERIT_ENV}-${LIBRARY_BUILD_TYPE}-${CURL_LINK_TYPE}-ssl-${OPENSSL_LINK_TYPE}-ipv6-sspi\\${CURL_LIBRARY_NAME}") + set(CURL_INCLUDE_DIRS "${CURL_ROOT_DIR}\\builds\\libcurl-vc15-${INHERIT_ENV}-${LIBRARY_BUILD_TYPE}-${CURL_LINK_TYPE}-ssl-${OPENSSL_LINK_TYPE}-ipv6-sspi\\include\\") + + message (STATUS "Constructed curl library path: ${CURL_LIBRARIES}") + message (STATUS "Constructed curl include path: ${CURL_INCLUDE_DIRS}") + + unset(INHERIT_ENV) + unset(LIBRARY_BUILD_TYPE) + unset(CURL_LIBRARY_NAME) + else() + if(CURL_LINK_TYPE STREQUAL "static") + add_definitions(-DCURL_STATICLIB) + endif() + + #if there isn't a customized openssl library and include, then use FindOpenSSL.cmake to find Openssl on Windows + if(NOT((DEFINED CURL_INCLUDE_DIRS) OR (DEFINED CURL_LIBRARIES))) + find_package(CURL REQUIRED) + endif() + endif() + + #Constructing OPENSSL path on windows. + if((DEFINED OPENSSL_ROOT_DIR) AND (NOT (OPENSSL_ROOT_DIR STREQUAL ""))) + if(CMAKE_CL_64) + set(INHERIT_ENV "x64") + else() + set(INHERIT_ENV "x86") + endif() + + if(OPENSSL_LINK_TYPE STREQUAL "static") + add_definitions(-DOPENSSL_STATICLIB) + set(OPENSSL_LIBRARY_NAME "ssleay32.lib") + set(OPENSSL_CRYPTO_LIBRARY_NAME "libeay32.lib") + else() + set(OPENSSL_LIBRARY_NAME "ssleay32.dll") + set(OPENSSL_CRYPTO_LIBRARY_NAME "libeay32.dll") + endif() + + set(OPENSSL_SSL_LIBRARY "${OPENSSL_ROOT_DIR}\\lib\\${CMAKE_BUILD_TYPE}\\${OPENSSL_LIBRARY_NAME}") + set(OPENSSL_CRYPTO_LIBRARY "${OPENSSL_ROOT_DIR}\\lib\\${CMAKE_BUILD_TYPE}\\${OPENSSL_CRYPTO_LIBRARY_NAME}") + set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}\\include\\openssl\\") + message (STATUS "Constructed openssl library path: ${OPENSSL_SSL_LIBRARY}") + message (STATUS "Constructed openssl include path: ${OPENSSL_INCLUDE_DIR}") + message (STATUS "Constructed openssl crypto library path: ${OPENSSL_CRYPTO_LIBRARY}") + unset(INHERIT_ENV) + unset(OPENSSL_LIBRARY_NAME) + unset(OPENSSL_CRYPTO_LIBRARY_NAME) + else() + if(OPENSSL_LINK_TYPE STREQUAL "static") + add_definitions(-DOPENSSL_STATICLIB) + endif() + + #if there isn't a customized openssl library and include, then use FindOpenSSL.cmake to find Openssl on Windows + if(NOT((DEFINED OPENSSL_INCLUDE_DIR) AND (DEFINED OPENSSL_CRYPTO_LIBRARY) AND (DEFINED OPENSSL_SSL_LIBRARY))) + message(STATUS "OpenSSL folder is not specified, need to find it automatically.") + find_package(OpenSSL REQUIRED) + endif() + endif() + + if(OPENSSL_LINK_TYPE STREQUAL "static") + add_definitions(-DOPENSSL_STATICLIB) + endif() add_definitions(-DUSE_OPENSSL) - find_package(OpenSSL REQUIRED) + set(OPENSSL_MSVC_STATIC_RT "true") + if (BUILD_WITH_MT) + set(CMAKE_CXX_FLAGS_RELEASE "/MT") + set(CMAKE_CXX_FLAGS_DEBUG "/MT") + endif() + #adding extra dependency libraries for windows + set(EXTRA_LIBRARIES ${EXTRA_LIBRARIES} rpcrt4 ws2_32 wldap32 crypt32 normaliz) + include_directories(${PROJECT_SOURCE_DIR}/include ${CURL_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${EXTRA_INCLUDE}) endif() -add_definitions(-std=c++11) -set(WARNING "-Wall -Wextra -Werror -pedantic -pedantic-errors") -set(CMAKE_CXX_FLAGS "${CMAKE_THREAD_LIBS_INIT} ${WARNING} ${CMAKE_CXX_FLAGS}") -include_directories(${PROJECT_SOURCE_DIR}/include ${CURL_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${UUID_INCLUDE_DIR} ${EXTRA_INCLUDE}) +if(CMAKE_COMPILER_IS_GNUCXX) + message(STATUS "GCC detected, adding compile flags") + add_definitions(-std=c++11) + set(WARNING "-Wall -Wextra -Werror -pedantic -pedantic-errors") + set(CMAKE_CXX_FLAGS "${CMAKE_THREAD_LIBS_INIT} ${WARNING} ${CMAKE_CXX_FLAGS}") +endif(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_MACOSX_RPATH ON) @@ -135,7 +249,11 @@ else () add_library(azure-storage-lite STATIC ${AZURE_STORAGE_LITE_HEADER} ${AZURE_STORAGE_LITE_SOURCE}) endif() -target_link_libraries(azure-storage-lite ${CURL_LIBRARIES} ${OPENSSL_CRYPTO_LIBRARY} ${OPENSSL_SSL_LIBRARY} ${UUID_LIBRARIES} ${EXTRA_LIBRARIES}) +if (NOT ${USE_OPENSSL}) + target_link_libraries(azure-storage-lite ${CURL_LIBRARIES} ${UUID_LIBRARIES} ${EXTRA_LIBRARIES}) +else() + target_link_libraries(azure-storage-lite ${CURL_LIBRARIES} ${OPENSSL_CRYPTO_LIBRARY} ${OPENSSL_SSL_LIBRARY} ${UUID_LIBRARIES} ${EXTRA_LIBRARIES}) +endif() if(BUILD_TESTS) add_subdirectory(test) diff --git a/CMakeSettings.json b/CMakeSettings.json index ab28b59..fea62b5 100644 --- a/CMakeSettings.json +++ b/CMakeSettings.json @@ -1,4 +1,16 @@ { + "environments": [ + { + "curlRootDir": "", + "opensslRootDir": "", + "buildWithMT": "true", //true or false + "buildSharedLibrary": "false", //true or false + "buildTests": "true", //true or false + "buildSamples": "true", //true or false + "opensslLinkType": "static", //static or dll + "curlLinkType": "static" //static or dll + } + ], "configurations": [ { "name": "Linux-Release", @@ -17,11 +29,11 @@ "variables": [ { "name": "BUILD_TESTS", - "value": "true" + "value": "${env.buildTests}" }, { "name": "BUILD_SAMPLES", - "value": "true" + "value": "${env.buildSamples}" } ] }, @@ -45,11 +57,203 @@ "variables": [ { "name": "BUILD_TESTS", - "value": "true" + "value": "${env.buildTests}" }, { "name": "BUILD_SAMPLES", - "value": "true" + "value": "${env.buildSamples}" + } + ] + }, + { + "name": "Windows-x86-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "buildRoot": "${env.LOCALAPPDATA}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", + "cmakeCommandArgs": "", + "ctestCommandArgs": "", + "buildCommandArgs": "", + "inheritEnvironments": [ "msvc_x86" ], + "variables": [ + { + "name": "CURL_ROOT_DIR", + "value": "${env.curlRootDir}" + }, + { + "name": "OPENSSL_ROOT_DIR", + "value": "${env.opensslRootDir}" + }, + { + "name": "BUILD_TESTS", + "value": "${env.buildTests}" + }, + { + "name": "BUILD_SAMPLES", + "value": "${env.buildSamples}" + }, + { + "name": "OPENSSL_MSVC_STATIC_RT", + "value": "${env.buildWithMT}" + }, + { + "name": "BUILD_WITH_MT", + "value": "${env.buildWithMT}" + }, + { + "name": "BUILD_SHARED_LIBS", + "value": "${env.buildSharedLibrary}" + }, + { + "name": "OPENSSL_LINK_TYPE", + "value": "${env.opensslLinkType}" + }, + { + "name": "CURL_LINK_TYPE", + "value": "${env.curlLinkType}" + } + ] + }, + { + "name": "Windows-x64-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "buildRoot": "${env.LOCALAPPDATA}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", + "cmakeCommandArgs": "", + "ctestCommandArgs": "", + "buildCommandArgs": "", + "inheritEnvironments": [ "msvc_x64" ], + "variables": [ + { + "name": "CURL_ROOT_DIR", + "value": "${env.curlRootDir}" + }, + { + "name": "OPENSSL_ROOT_DIR", + "value": "${env.opensslRootDir}" + }, + { + "name": "BUILD_TESTS", + "value": "${env.buildTests}" + }, + { + "name": "BUILD_SAMPLES", + "value": "${env.buildSamples}" + }, + { + "name": "OPENSSL_MSVC_STATIC_RT", + "value": "${env.buildWithMT}" + }, + { + "name": "BUILD_WITH_MT", + "value": "${env.buildWithMT}" + }, + { + "name": "BUILD_SHARED_LIBS", + "value": "${env.dynamicLinking}" + }, + { + "name": "OPENSSL_LINK_TYPE", + "value": "${env.opensslLinkType}" + }, + { + "name": "CURL_LINK_TYPE", + "value": "${env.curlLinkType}" + } + ] + }, + { + "name": "Windows-x86-Release", + "generator": "Ninja", + "configurationType": "Release", + "buildRoot": "${env.LOCALAPPDATA}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", + "cmakeCommandArgs": "", + "ctestCommandArgs": "", + "buildCommandArgs": "", + "inheritEnvironments": [ "msvc_x86" ], + "variables": [ + { + "name": "CURL_ROOT_DIR", + "value": "${env.curlRootDir}" + }, + { + "name": "OPENSSL_ROOT_DIR", + "value": "${env.opensslRootDir}" + }, + { + "name": "BUILD_TESTS", + "value": "${env.buildTests}" + }, + { + "name": "BUILD_SAMPLES", + "value": "${env.buildSamples}" + }, + { + "name": "OPENSSL_MSVC_STATIC_RT", + "value": "${env.buildWithMT}" + }, + { + "name": "BUILD_WITH_MT", + "value": "${env.buildWithMT}" + }, + { + "name": "BUILD_SHARED_LIBS", + "value": "${env.buildSharedLibrary}" + }, + { + "name": "OPENSSL_LINK_TYPE", + "value": "${env.opensslLinkType}" + }, + { + "name": "CURL_LINK_TYPE", + "value": "${env.curlLinkType}" + } + ] + }, + { + "name": "Windows-x64-Release", + "generator": "Ninja", + "configurationType": "Release", + "buildRoot": "${env.LOCALAPPDATA}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", + "cmakeCommandArgs": "", + "ctestCommandArgs": "", + "buildCommandArgs": "", + "inheritEnvironments": [ "msvc_x64" ], + "variables": [ + { + "name": "CURL_ROOT_DIR", + "value": "${env.curlRootDir}" + }, + { + "name": "OPENSSL_ROOT_DIR", + "value": "${env.opensslRootDir}" + }, + { + "name": "BUILD_TESTS", + "value": "${env.buildTests}" + }, + { + "name": "BUILD_SAMPLES", + "value": "${env.buildSamples}" + }, + { + "name": "OPENSSL_MSVC_STATIC_RT", + "value": "${env.buildWithMT}" + }, + { + "name": "BUILD_WITH_MT", + "value": "${env.buildWithMT}" + }, + { + "name": "BUILD_SHARED_LIBS", + "value": "${env.buildSharedLibrary}" + }, + { + "name": "OPENSSL_LINK_TYPE", + "value": "${env.opensslLinkType}" + }, + { + "name": "CURL_LINK_TYPE", + "value": "${env.curlLinkType}" } ] } diff --git a/README.md b/README.md index b84cfb4..f501d69 100644 --- a/README.md +++ b/README.md @@ -25,12 +25,18 @@ The full supported Azure Storage API can be found in the following list, please - [Append Block](https://docs.microsoft.com/en-us/rest/api/storageservices/append-block). ## Installation - -### Clone the latest code from this repository: +### Build this library on Linux +Project dependencies: + - GNUTLS(or Openssl v1.0.1) + - libcurl v7.35.0 + - CMake v2.8.12.2 + - g++ v4.8.2 + - UUID 2.13.1-0.4 +#### Clone the latest code from this repository: ``` git clone https://github.com/azure/azure-storage-cpplite.git ``` -### Install the dependencies, e.g. on Ubuntu: +#### Install the dependencies, e.g. on Ubuntu: ``` sudo apt-get install libssl-dev libcurl4-openssl-dev cmake g++ uuid-dev ``` @@ -40,7 +46,7 @@ sudo yum install openssl-devel.x86_64 libcurl-devel.x86_64 cmake.x86_64 gcc-c++. ``` Please be aware that RHEL6 comes with gcc version 4.4.7, which does not meet the requirement of this SDK. In order to use this SDK, [devtoolset](http://linux.web.cern.ch/linux/devtoolset/#install) needs to be installed properly. Please be aware that on some Linux distributions, pkg-config is not properly installed that would result in CMake to not behave as expected. Installing pkg-config or updating it will eliminate the potential issue. The tested version of pkg-config is 0.29.1-0. -### Build and install azure-storage-cpplite: +#### Build and install azure-storage-cpplite: ``` cd azure-storage-cpplite mkdir build.release @@ -48,9 +54,109 @@ cd build.release CXX=g++ cmake .. -DCMAKE_BUILD_TYPE=Release -DUSE_OPENSSL=true sudo make install ``` -### Use GNUTLS instead of OpenSSL: +#### Use GNUTLS instead of OpenSSL: Alternatively, you can use GNUTLS instead of OpenSSL. Simply install GNUTLS and remove the argument `-DUSE_OPENSSL` during build. +### Build this library on Windows +Project dependencies: + - Openssl v1.0.2o + - libcurl v7.60.0 + - CMake v2.8.12.2 + - Visual Studio 2017 + - Perl (If OpenSSL needs to be built manually) +#### Clone the latest code from this repository: +``` +git clone https://github.com/azure/azure-storage-cpplite.git +``` +#### Prepare and build the dependencies. +There are two major dependencies on Windows: libcurl and OpenSSL. You can reference the how-tos in this readme or install your own choice of pre-built binaries. +##### How to build libcurl and openssl? +You can use the following guide to build libcurl and openssl on your own. Note that Perl must be installed to build OpenSSL. +Clone the source code of libcurl and OpenSSL: +``` +git clone --branch curl-7_60_0 https://github.com/curl/curl.git +git clone --branch OpenSSL_1_0_2o https://github.com/openssl/openssl.git +``` + +Build OpenSSL first, e.g. if you want to build x86-debug version, note that the perlpath should change to your systems perl install path: +``` +.\curl\projects\build-openssl.bat vc14.1 x64 debug .\openssl\ -perlpath C:\Strawberry +``` + +Then build libcurl: +Run the setup batch file +``` +.\curl\buildconf.bat +``` +Modify .\curl\winbuild\MakefileBuild.vc to support linking with different configuration type. +Change line: +``` +DEVEL_LIB = $(WITH_DEVEL)/lib +``` +To: +``` +!IF "$(DEBUG)"=="yes" +DEVEL_LIB = $(WITH_DEVEL)/lib/Debug +!ELSE +DEVEL_LIB = $(WITH_DEVEL)/lib/Release +!ENDIF +``` +Create `.\curl\deps` folder. +Add `include`, `lib\Debug` and `lib\Release` to `.\curl\deps` folder. +Copy OpenSSL's include and built libraries into created `.\curl\deps` folder: + 1. Create `openssl` folder in `.curl\deps\include` + 2. Copy `.\openssl\inc32\openssl` into `.\curl\deps\include\openssl`, and you will see `.\curl\deps\include\openssl\openssl`. Please note the duplicated `openssl` in path is somehow necessary for curl build-script. + 3. Copy `.\openssl\build\Win32\VC14.1\LIB Release\*.lib` to `.\curl\deps\lib\Release` folder if static libraries are built, otherwise copy the `*.dll` instead. +Open Visual Studio CMD tool, navigate to `.\curl\winbuild` and start building, e.g. Run 'x64 Native Tools command Prompt for VS2017.exe' and run: +``` +nmake /f Makefile.vc mode=static VC=15 MACHINE=x64 WITH_SSL=static DEBUG=yes WITH_DEVEL=..\deps RTLIBCFG=static +``` +#### Build azure-storage-cpplite using CMake in command line +Note that the `` should be the absolute path constructed in curl directory as dependency when building curl, normally it should be `\deps`. Also, `` should be absolute path. Using relative path can cause build to fail. +``` +cd azure-storage-cpplite +mkdir build.release +cd build.release +cmake .. -DCURL_ROOT_DIR="" -DOPENSSL_ROOT_DIR="" +MSBuild.exe azurestoragelite.sln /p:Configuration=Release +``` +If you have libcurl and OpenSSL built or installed by yourself with another approach, you can specify the path to the library and headers of them instead: +``` +cmake .. -DCURL_LIBRARIES="" -DCURL_INCLUDE_DIRS="" -DOPENSSL_SSL_LIBRARY="" -DOPENSSL_CRYPTO_LIBRARY="" -DOPENSSL_INCLUDE_DIR="" +MSBuild.exe azurestoragelite.sln /p:Configuration=Release +``` +There are some advanced options to config the build when using cmake commands: +`-DBUILD_TESTS` : specify `true` or `false` to control if tests should be built. +`-DBUILD_SAMPLES` : specify `true` or `false` to control if samples should be built. +`-DOPENSSL_MSVC_STATIC_RT` : specify `true` or `false` to control if the library is building into static library. Note this should be used together with `-DBUILD_SHARED_LIBS=` either `ON` or `OFF`. +`-DBUILD_WITH_MT` : specify `true` or `false` to control if the library is using `/MT` or `/MTd`. +`-DOPENSSL_LINK_TYPE` : specify `static` or `dll` to control if OpenSSL should be linked statically. +`-DCURL_LINK_TYPE` : specify `static` or `dll` to control if libcurl should be linked statically. +`-DCMAKE_GENERATOR_PLATFORM` : specify `x86` or `x64` to config the generator platform type. +`-DCMAKE_BUILD_TYPE` : specify `Debug` or `Release` to config the build type. +#### Build azure-storage-cpplite using Visual Studio 2017 +Use Visual Studio 2017 to open the folder that contains this repository. Modify the `environments` in `CMakeSettings.json`. E.g.: +``` + "environments": [ + { + "curlRootDir": "E:\\dev\\src\\cpp\\curl", + "opensslRootDir": "E:\\dev\\src\\cpp\\curl\\deps", + "buildWithMT": "true", //true or false + "buildSharedLibrary": "false", //true or false + "buildTests": "true", //true or false + "buildSamples": "true", //true or false + "opensslLinkType": "static", //static or dll + "curlLinkType": "static" //static or dll + } + ] +``` + +#### Build dependencies with /MD (/MDd) options instead. +If need to build /MD(/MDd) version, there are two things to do when building OpenSSL: + 1. Modify .\openssl\ms\nt.mak, change CFLAG's from `/MT` to `/MD` + 2. Comment out this line in .\curl\projects\build-openssl.bat: `perl Configure debug-VC-WIN32 no-asm --prefix=%CD%` +When building libcurl, remove the trailing `RTLIBCFG=static` option will build with `/MD` or `/MDd` + ### Build static library instead of dynamic libraries. By default, dynamic libraries are built. Adding `-DBUILD_SHARED_LIBS=OFF` will build static library instead. @@ -101,16 +207,8 @@ When contributing to this client library, there are following ground rules: 4. Introducing new dependency should be done with much great caution. Any new dependency should introduce significant performance improvement or unblock critical user scenario. ### Build Test +- Dev dependency: catch2. Download [Catch2 single header version](https://raw.githubusercontent.com/catchorg/Catch2/master/single_include/catch2/catch.hpp) and put it in the folder `.\test\catch2\`. Add `-DBUILD_TESTS=true` when building the repository. Please modify the [connection string here](https://github.com/azure/azure-storage-cpplite/blob/master/test/test_base.h#L18) in `.\test\test_base.h` line 18 `static std::string sscs = "DefaultEndpointsProtocol=https;";` to successfully run the tests. All the tests use standard Azure Storage account. -#### *Please note that in order to run test, a minimum version of g++ 5.1 is required.* - -### Dependencies -- Project dependencies: - - GNUTLS(or Openssl v1.0.1) - - libcurl v7.35.0 - - CMake v2.8.12.2 - - g++ v4.8.2 - - UUID 2.13.1-0.4 -- Dev dependency: catch2. +#### *Please note that in order to run test, a minimum version of g++ 5.1 is required on Linux, and Visual Studio 2017 is required on Windows.* diff --git a/include/hash.h b/include/hash.h index 5887917..35d1f78 100644 --- a/include/hash.h +++ b/include/hash.h @@ -3,10 +3,6 @@ #include #include -#ifdef _WIN32 -#include -#include -#else #ifdef USE_OPENSSL #include #else @@ -14,54 +10,9 @@ #include #endif #define SHA256_DIGEST_LENGTH 32 -#endif #include "storage_EXPORTS.h" namespace azure { namespace storage_lite { - -#ifdef _WIN32 - class hash_algorithm_base {}; - - class hmac_sha256_hash_algorithm : public hash_algorithm_base - { - BCRYPT_ALG_HANDLE _algorithm_handle; - public: - BCRYPT_ALG_HANDLE handle() { return _algorithm_handle; } - - hmac_sha256_hash_algorithm() - { - NTSTATUS status = BCryptOpenAlgorithmProvider(&_algorithm_handle, BCRYPT_SHA256_ALGORITHM /* BCRYPT_MD5_ALGORITHM */, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG /* 0 */); - if (status != 0) { - throw std::system_error(status, std::system_category()); - } - } - - ~hmac_sha256_hash_algorithm() - { - BCryptCloseAlgorithmProvider(_algorithm_handle, 0); - } - }; - - template - class hash_provider_base - { - static std::string hash_impl(const std::string &input, const std::vector &key) = delete; - public: - static std::string hash(const std::string &input, const std::vector &key - { - return Hash_Provider::hash_impl(input, key); - } - }; - - class hmac_sha256_hash_provider : public hash_provider_base - { - static hmac_sha256_hash_algorithm _algorithm; - public: - AZURE_STORAGE_API static std::string hash_impl(const std::string &input, const std::vector &key); - }; -#else - std::string hash(const std::string &to_sign, const std::vector &key); -#endif - + AZURE_STORAGE_API std::string hash(const std::string &to_sign, const std::vector &key); }} // azure::storage_lite diff --git a/include/http/libcurl_http_client.h b/include/http/libcurl_http_client.h index 68d3b02..2077295 100644 --- a/include/http/libcurl_http_client.h +++ b/include/http/libcurl_http_client.h @@ -19,6 +19,9 @@ #include "http_base.h" +#pragma push_macro("min") +#undef min + namespace azure { namespace storage_lite { class CurlEasyClient; @@ -273,3 +276,5 @@ namespace azure { namespace storage_lite { }; }} // azure::storage_lite + +#pragma pop_macro("min") diff --git a/include/logging.h b/include/logging.h new file mode 100644 index 0000000..eb832dd --- /dev/null +++ b/include/logging.h @@ -0,0 +1,98 @@ +#pragma once + +#include +#include +#include + +#ifdef _WIN32 +#include +#pragma warning(disable : 4996) +#define _SNPRINTF _snprintf +#else +#include +#define _SNPRINTF snprintf +#endif + +#include "storage_EXPORTS.h" + +constexpr auto MAX_LOG_LENGTH = 8192u; + +namespace azure { namespace storage_lite { + + enum log_level { + trace = 0x0, + debug, + info, + warn, + error, + critical, + none + }; + + class logger + { + public: + static void log(log_level level, const std::string& msg) + { + s_logger(level, msg); + } + + template + static void log(log_level level, const char* format, Args ... args) + { + if (level > log_level::critical) + { + return; // does not support higher level logging. + } + size_t size = _SNPRINTF(nullptr, 0, format, args ...) + 1; + // limit the maximum size of this log string to 8kb, as the buffer needs + // to be allocated to a continuous memory and is likely to fail + // when the size is relatively big. + size = size > MAX_LOG_LENGTH ? MAX_LOG_LENGTH : size; + std::unique_ptr buf(new char[size]); + _SNPRINTF(buf.get(), size, format, args ...); + auto msg = std::string(buf.get(), buf.get() + size - 1); + log(level, msg); + } + + static void debug(const std::string& msg) + { + log(log_level::debug, msg); + } + + static void info(const std::string& msg) + { + log(log_level::info, msg); + } + + static void warn(const std::string& msg) + { + log(log_level::warn, msg); + } + + static void error(const std::string& msg) + { + log(log_level::error, msg); + } + + static void critical(const std::string& msg) + { + log(log_level::critical, msg); + } + + static void trace(const std::string& msg) + { + log(log_level::trace, msg); + } + + static void set_logger(const std::function& new_logger) + { + s_logger = new_logger; + } + + protected: + static std::function s_logger; + + static void simple_logger(log_level level, const std::string& msg); + }; +}} \ No newline at end of file diff --git a/include/retry.h b/include/retry.h index d976c20..d7dc4f5 100644 --- a/include/retry.h +++ b/include/retry.h @@ -9,6 +9,9 @@ #include "http_base.h" #include "utility.h" +#pragma push_macro("min") +#undef min + namespace azure { namespace storage_lite { class retry_info @@ -98,3 +101,5 @@ namespace azure { namespace storage_lite { }; }} // azure::storage_lite + +#pragma pop_macro("min") diff --git a/include/storage_EXPORTS.h b/include/storage_EXPORTS.h index 1976814..58b592c 100644 --- a/include/storage_EXPORTS.h +++ b/include/storage_EXPORTS.h @@ -2,6 +2,6 @@ #ifdef _WIN32 #define AZURE_STORAGE_API __declspec(dllexport) -#else /* ifdef WIN32 */ +#else /* ifdef _WIN32 */ #define AZURE_STORAGE_API #endif diff --git a/include/utility.h b/include/utility.h index 19c1486..f08fc0d 100644 --- a/include/utility.h +++ b/include/utility.h @@ -11,6 +11,9 @@ #include "storage_request_base.h" #include "storage_url.h" +#pragma push_macro("max") +#undef max + namespace azure { namespace storage_lite { enum class date_format @@ -124,6 +127,7 @@ namespace azure { namespace storage_lite { AZURE_STORAGE_API std::string get_uuid(); + AZURE_STORAGE_API bool create_or_resize_file(const std::string& path, unsigned long long length) noexcept; inline bool unsuccessful(http_base::http_code status_code) { @@ -182,3 +186,5 @@ namespace azure { namespace storage_lite { } }} // azure::storage_lite + +#pragma pop_macro("max") diff --git a/src/blob/blob_client.cpp b/src/blob/blob_client.cpp index be2ada4..3c20c30 100644 --- a/src/blob/blob_client.cpp +++ b/src/blob/blob_client.cpp @@ -1,5 +1,11 @@ #include #include + +#ifdef _WIN32 +#include +typedef SSIZE_T ssize_t; +#endif + #include "blob/blob_client.h" #include "blob/download_blob_request.h" diff --git a/src/blob/blob_client_wrapper.cpp b/src/blob/blob_client_wrapper.cpp index c98aefa..e104967 100644 --- a/src/blob/blob_client_wrapper.cpp +++ b/src/blob/blob_client_wrapper.cpp @@ -1,20 +1,19 @@ /* C++ interface wrapper for blob client * No exceptions will throw. */ -#include -#ifdef __linux__ -#include -#else -#include -#endif //__linux__ -#include -#include + #include #include #include "blob/blob_client.h" +#include "logging.h" #include "storage_errno.h" +#pragma push_macro("max") +#undef max +#pragma push_macro("min") +#undef min + namespace azure { namespace storage_lite { const unsigned long long DOWNLOAD_CHUNK_SIZE = 16 * 1024 * 1024; @@ -152,7 +151,7 @@ namespace azure { namespace storage_lite { } catch(const std::exception &ex) { - syslog(LOG_ERR, "Failed to create blob client. ex.what() = %s.", ex.what()); + logger::log(log_level::error, "Failed to create blob client. ex.what() = %s.", ex.what()); errno = unknown_error; return blob_client_wrapper(false); } @@ -190,7 +189,7 @@ namespace azure { namespace storage_lite { } catch(std::exception& ex) { - syslog(LOG_ERR, "Unknown failure in create_container. ex.what() = %s, container = %s.", ex.what(), container.c_str()); + logger::log(log_level::error, "Unknown failure in create_container. ex.what() = %s, container = %s.", ex.what(), container.c_str()); errno = unknown_error; return; } @@ -225,7 +224,7 @@ namespace azure { namespace storage_lite { } catch(std::exception& ex) { - syslog(LOG_ERR, "Unknown failure in delete_container. ex.what() = %s, container = %s.", ex.what(), container.c_str()); + logger::log(log_level::error, "Unknown failure in delete_container. ex.what() = %s, container = %s.", ex.what(), container.c_str()); errno = unknown_error; return; } @@ -255,14 +254,14 @@ namespace azure { namespace storage_lite { } else { - syslog(LOG_ERR, "Unknown failure in container_exists. No exception, but the container property object is invalid. errno = %d.", errno); + logger::log(log_level::error, "Unknown failure in container_exists. No exception, but the container property object is invalid. errno = %d.", errno); errno = unknown_error; return false; } } catch(std::exception& ex) { - syslog(LOG_ERR, "Unknown failure in container_exists. ex.what() = %s, container = %s.", ex.what(), container.c_str()); + logger::log(log_level::error, "Unknown failure in container_exists. ex.what() = %s, container = %s.", ex.what(), container.c_str()); errno = unknown_error; return false; } @@ -295,7 +294,7 @@ namespace azure { namespace storage_lite { } catch(std::exception& ex) { - syslog(LOG_ERR, "Unknown failure in list_containers. ex.what() = %s, prefix = %s.", ex.what(), prefix.c_str()); + logger::log(log_level::error, "Unknown failure in list_containers. ex.what() = %s, prefix = %s.", ex.what(), prefix.c_str()); errno = unknown_error; return std::vector(); } @@ -332,7 +331,7 @@ namespace azure { namespace storage_lite { } catch(std::exception& ex) { - syslog(LOG_ERR, "Unknown failure in list_blobs_hierarchial. ex.what() = %s, container = %s, prefix = %s.", ex.what(), container.c_str(), prefix.c_str()); + logger::log(log_level::error, "Unknown failure in list_blobs_hierarchial. ex.what() = %s, container = %s, prefix = %s.", ex.what(), container.c_str(), prefix.c_str()); errno = unknown_error; return list_blobs_segmented_response(); } @@ -359,7 +358,7 @@ namespace azure { namespace storage_lite { catch(std::exception& ex) { // TODO open failed - syslog(LOG_ERR, "Failure to open the input stream in put_blob. ex.what() = %s, sourcePath = %s.", ex.what(), sourcePath.c_str()); + logger::log(log_level::error, "Failure to open the input stream in put_blob. ex.what() = %s, sourcePath = %s.", ex.what(), sourcePath.c_str()); errno = unknown_error; return; } @@ -379,7 +378,7 @@ namespace azure { namespace storage_lite { } catch(std::exception& ex) { - syslog(LOG_ERR, "Failure to upload the blob in put_blob. ex.what() = %s, container = %s, blob = %s, sourcePath = %s.", ex.what(), container.c_str(), blob.c_str(), sourcePath.c_str()); + logger::log(log_level::error, "Failure to upload the blob in put_blob. ex.what() = %s, container = %s, blob = %s, sourcePath = %s.", ex.what(), container.c_str(), blob.c_str(), sourcePath.c_str()); errno = unknown_error; } @@ -390,7 +389,7 @@ namespace azure { namespace storage_lite { catch(std::exception& ex) { // TODO close failed - syslog(LOG_ERR, "Failure to close the input stream in put_blob. ex.what() = %s, container = %s, blob = %s, sourcePath = %s.", ex.what(), container.c_str(), blob.c_str(), sourcePath.c_str()); + logger::log(log_level::error, "Failure to close the input stream in put_blob. ex.what() = %s, container = %s, blob = %s, sourcePath = %s.", ex.what(), container.c_str(), blob.c_str(), sourcePath.c_str()); errno = unknown_error; } } @@ -426,7 +425,7 @@ namespace azure { namespace storage_lite { } catch(std::exception& ex) { - syslog(LOG_ERR, "Unknown failure in upload_block_blob_from_stream. ex.what() = %s, container = %s, blob = %s.", ex.what(), container.c_str(), blob.c_str()); + logger::log(log_level::error, "Unknown failure in upload_block_blob_from_stream. ex.what() = %s, container = %s, blob = %s.", ex.what(), container.c_str(), blob.c_str()); errno = unknown_error; } } @@ -481,7 +480,7 @@ namespace azure { namespace storage_lite { std::ifstream ifs(sourcePath); if(!ifs) { - syslog(LOG_ERR, "Failed to open the input stream in upload_file_to_blob. errno = %d, sourcePath = %s.", errno, sourcePath.c_str()); + logger::log(log_level::error, "Failed to open the input stream in upload_file_to_blob. errno = %d, sourcePath = %s.", errno, sourcePath.c_str()); errno = unknown_error; return; } @@ -506,20 +505,20 @@ namespace azure { namespace storage_lite { if (0 != result) { break; } - int length = block_size; + long long length = block_size; if(offset + length > fileSize) { length = fileSize - offset; } - char* buffer = (char*)malloc(block_size); + char* buffer = (char*)malloc(static_cast(block_size)); // This cast is save because block size should always be lower than 4GB if (!buffer) { result = 12; break; } if(!ifs.read(buffer, length)) { - syslog(LOG_ERR, "Failed to read from input stream in upload_file_to_blob. sourcePath = %s, container = %s, blob = %s, offset = %lld, length = %d.", sourcePath.c_str(), container.c_str(), blob.c_str(), offset, length); + logger::log(log_level::error, "Failed to read from input stream in upload_file_to_blob. sourcePath = %s, container = %s, blob = %s, offset = %lld, length = %d.", sourcePath.c_str(), container.c_str(), blob.c_str(), offset, length); result = unknown_error; break; } @@ -587,7 +586,7 @@ namespace azure { namespace storage_lite { if(!r.success()) { result = std::stoi(r.error().code); - syslog(LOG_ERR, "put_block_list failed in upload_file_to_blob. error code = %d, sourcePath = %s, container = %s, blob = %s.", result, sourcePath.c_str(), container.c_str(), blob.c_str()); + logger::log(log_level::error, "put_block_list failed in upload_file_to_blob. error code = %d, sourcePath = %s, container = %s, blob = %s.", result, sourcePath.c_str(), container.c_str(), blob.c_str()); if (0 == result) { result = unknown_error; } @@ -633,7 +632,7 @@ namespace azure { namespace storage_lite { } catch(std::exception& ex) { - syslog(LOG_ERR, "Unknown failure in download_blob_to_stream. ex.what() = %s, container = %s, blob = %s.", ex.what(), container.c_str(), blob.c_str()); + logger::log(log_level::error, "Unknown failure in download_blob_to_stream. ex.what() = %s, container = %s, blob = %s.", ex.what(), container.c_str(), blob.c_str()); errno = unknown_error; return; } @@ -657,7 +656,7 @@ namespace azure { namespace storage_lite { firstChunk = m_blobClient->get_chunk_to_stream_sync(container, blob, 0, DOWNLOAD_CHUNK_SIZE, os); os.close(); if (!os) { - syslog(LOG_ERR, "get_chunk_to_stream_async failed for firstchunk in download_blob_to_file. container = %s, blob = %s, destPath = %s.", container.c_str(), blob.c_str(), destPath.c_str()); + logger::log(log_level::error, "get_chunk_to_stream_async failed for firstchunk in download_blob_to_file. container = %s, blob = %s, destPath = %s.", container.c_str(), blob.c_str(), destPath.c_str()); errno = unknown_error; return; } @@ -680,16 +679,8 @@ namespace azure { namespace storage_lite { const auto originalEtag = firstChunk.response().etag; const auto length = static_cast(firstChunk.response().totalSize); - // Resize the target file. - auto fd = open(destPath.c_str(), O_WRONLY, 0770); - if (-1 == fd) { - return; - } - if (-1 == ftruncate(fd, length)) { - close(fd); - return; - } - close(fd); + // Create or resize the target file if already exist. + create_or_resize_file(destPath, length); // Download the rest. const auto left = length - firstChunk.response().size; @@ -718,7 +709,7 @@ namespace azure { namespace storage_lite { } // Check for any writing errors. if (!output) { - syslog(LOG_ERR, "get_chunk_to_stream_async failure in download_blob_to_file. container = %s, blob = %s, destPath = %s, offset = %llu, range = %llu.", container.c_str(), blob.c_str(), destPath.c_str(), offset, range); + logger::log(log_level::error, "get_chunk_to_stream_async failure in download_blob_to_file. container = %s, blob = %s, destPath = %s, offset = %llu, range = %llu.", container.c_str(), blob.c_str(), destPath.c_str(), offset, range); return unknown_error; } return 0; @@ -740,7 +731,7 @@ namespace azure { namespace storage_lite { } catch(std::exception& ex) { - syslog(LOG_ERR, "Unknown failure in download_blob_to_file. ex.what() = %s, container = %s, blob = %s, destPath = %s.", ex.what(), container.c_str(), blob.c_str(), destPath.c_str()); + logger::log(log_level::error, "Unknown failure in download_blob_to_file. ex.what() = %s, container = %s, blob = %s, destPath = %s.", ex.what(), container.c_str(), blob.c_str(), destPath.c_str()); errno = unknown_error; return; } @@ -773,7 +764,7 @@ namespace azure { namespace storage_lite { } catch(std::exception& ex) { - syslog(LOG_ERR, "Unknown failure in get_blob_property. ex.what() = %s, container = %s, blob = %s.", ex.what(), container.c_str(), blob.c_str()); + logger::log(log_level::error, "Unknown failure in get_blob_property. ex.what() = %s, container = %s, blob = %s.", ex.what(), container.c_str(), blob.c_str()); errno = unknown_error; return blob_property(false); } @@ -799,7 +790,7 @@ namespace azure { namespace storage_lite { } catch(std::exception& ex) { - syslog(LOG_ERR, "Unknown failure in blob_exists. ex.what() = %s, container = %s, blob = %s.", ex.what(), container.c_str(), blob.c_str()); + logger::log(log_level::error, "Unknown failure in blob_exists. ex.what() = %s, container = %s, blob = %s.", ex.what(), container.c_str(), blob.c_str()); errno = unknown_error; return false; } @@ -835,7 +826,7 @@ namespace azure { namespace storage_lite { } catch(std::exception& ex) { - syslog(LOG_ERR, "Unknown failure in delete_blob. ex.what() = %s, container = %s, blob = %s.", ex.what(), container.c_str(), blob.c_str()); + logger::log(log_level::error, "Unknown failure in delete_blob. ex.what() = %s, container = %s, blob = %s.", ex.what(), container.c_str(), blob.c_str()); errno = unknown_error; return; } @@ -873,10 +864,13 @@ namespace azure { namespace storage_lite { } catch(std::exception& ex) { - syslog(LOG_ERR, "Unknown failure in start_copy. ex.what() = %s, sourceContainer = %s, sourceBlob = %s, destContainer = %s, destBlob = %s.", ex.what(), sourceContainer.c_str(), sourceBlob.c_str(), destContainer.c_str(), destBlob.c_str()); + logger::log(log_level::error, "Unknown failure in start_copy. ex.what() = %s, sourceContainer = %s, sourceBlob = %s, destContainer = %s, destBlob = %s.", ex.what(), sourceContainer.c_str(), sourceBlob.c_str(), destContainer.c_str(), destBlob.c_str()); errno = unknown_error; return; } } }} // azure::storage_lite + +#pragma pop_macro("min") +#pragma pop_macro("max") diff --git a/src/hash.cpp b/src/hash.cpp index 9bea893..5741f17 100644 --- a/src/hash.cpp +++ b/src/hash.cpp @@ -3,51 +3,6 @@ #include "base64.h" namespace azure { namespace storage_lite { -#ifdef _WIN32 - hmac_sha256_hash_algorithm hmac_sha256_hash_provider::_algorithm; - - std::string hmac_sha256_hash_provider::hash_impl(const std::string &input, const std::vector &key) - { - ULONG object_size = 0; - ULONG size_length = 0; - - NTSTATUS status = BCryptGetProperty(_algorithm.handle(), BCRYPT_OBJECT_LENGTH, (PUCHAR)&object_size, sizeof(ULONG), &size_length, 0); - if (status != 0) - { - throw std::system_error(status, std::system_category()); - } - std::vector hash_object(object_size); - - BCRYPT_HASH_HANDLE hash_handle; - status = BCryptCreateHash(_algorithm.handle(), &hash_handle, (PUCHAR)hash_object.data(), (ULONG)hash_object.size(), (PUCHAR)key.data(), (ULONG)key.size(), 0); - if (status != 0) - { - throw std::system_error(status, std::system_category()); - } - - status = BCryptHashData(hash_handle, (PUCHAR)input.data(), (ULONG)input.size(), 0); - if (status != 0) - { - throw std::system_error(status, std::system_category()); - } - - status = BCryptGetProperty(hash_handle, BCRYPT_HASH_LENGTH, (PUCHAR)&object_size, sizeof(ULONG), &size_length, 0); - if (status != 0) - { - throw std::system_error(status, std::system_category()); - } - std::vector hash(object_size); - - status = BCryptFinishHash(hash_handle, hash.data(), (ULONG)hash.size(), 0); - if (status != 0 && status != 0xc0000008) - { - throw std::system_error(status, std::system_category()); - } - - status = BCryptDestroyHash(hash_handle); - return to_base64(hash); - } -#else std::string hash(const std::string &to_sign, const std::vector &key) { unsigned int l = SHA256_DIGEST_LENGTH; @@ -57,17 +12,17 @@ namespace azure { namespace storage_lite { #if OPENSSL_VERSION_NUMBER < 0x10100000L HMAC_CTX ctx; HMAC_CTX_init(&ctx); - HMAC_Init_ex(&ctx, key.data(), key.size(), EVP_sha256(), NULL); + HMAC_Init_ex(&ctx, key.data(), static_cast(key.size()), EVP_sha256(), NULL); HMAC_Update(&ctx, (const unsigned char*)to_sign.c_str(), to_sign.size()); HMAC_Final(&ctx, digest, &l); HMAC_CTX_cleanup(&ctx); #else - HMAC_CTX *ctx = HMAC_CTX_new(); + HMAC_CTX * ctx = HMAC_CTX_new(); HMAC_CTX_reset(ctx); HMAC_Init_ex(ctx, key.data(), key.size(), EVP_sha256(), NULL); HMAC_Update(ctx, (const unsigned char*)to_sign.c_str(), to_sign.size()); HMAC_Final(ctx, digest, &l); - HMAC_CTX_free(ctx); + HMAC_CTX_free(ctx); #endif #else gnutls_hmac_fast(GNUTLS_MAC_SHA256, key.data(), key.size(), (const unsigned char *)to_sign.data(), to_sign.size(), digest); @@ -75,6 +30,4 @@ namespace azure { namespace storage_lite { return to_base64(std::vector(digest, digest + l)); } -#endif - }} // azure::storage_lite diff --git a/src/logging.cpp b/src/logging.cpp new file mode 100644 index 0000000..bc48b30 --- /dev/null +++ b/src/logging.cpp @@ -0,0 +1,26 @@ +#include "logging.h" + +namespace azure { namespace storage_lite { + + std::function logger::s_logger = logger::simple_logger; + +#ifdef _WIN32 + void logger::simple_logger(log_level level, const std::string& msg) + { + //Do nothing for now. + //TODO: integrate with Windows trace log. + } +#else + int get_syslog_priority(log_level level) + { + static indexing = { LOG_DEBUG, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERR, LOG_CRIT }; + + return indexing[level]; + } + + void logger::simple_logger(log_level level, const std::string& msg) + { + syslog(get_syslog_priority(level), msg.c_str()); + } +#endif +}} diff --git a/src/storage_credential.cpp b/src/storage_credential.cpp index 88c8448..0dc3f3e 100644 --- a/src/storage_credential.cpp +++ b/src/storage_credential.cpp @@ -57,11 +57,7 @@ namespace azure { namespace storage_lite { } std::string authorization("SharedKey "); -#ifdef _WIN32 - authorization.append(m_account_name).append(":").append(hmac_sha256_hash_provider::hash(string_to_sign, m_account_key)); -#else authorization.append(m_account_name).append(":").append(hash(string_to_sign, m_account_key)); -#endif h.add_header(constants::header_authorization, authorization); } diff --git a/src/utility.cpp b/src/utility.cpp index ea34c00..4252749 100644 --- a/src/utility.cpp +++ b/src/utility.cpp @@ -4,24 +4,65 @@ #include "constants.h" -#ifdef WIN32 +#ifdef _WIN32 #include +#include #else #include +#include +#include +#include #endif namespace azure { namespace storage_lite { std::string get_uuid() { + std::string res; +#ifdef _WIN32 + UUID uuid; + UuidCreate(&uuid); + char* uuid_cstr = nullptr; + UuidToString(&uuid, reinterpret_cast(uuid_cstr)); + res = std::string(uuid_cstr); + RpcStringFreeA(reinterpret_cast(uuid_cstr)); +#else uuid_t uuid; char uuid_cstr[37]; // 36 byte uuid plus null. uuid_generate(uuid); uuid_unparse(uuid, uuid_cstr); + res = std::string(uuid_cstr); +#endif return std::string(uuid_cstr); } + bool create_or_resize_file(const std::string& path, unsigned long long length) noexcept + { +#ifdef _WIN32 + try + { + std::experimental::filesystem::resize_file(path, static_cast(length)); + } + catch (...) + { + return false; + } + return true; +#else + auto fd = open(path.c_str(), O_WRONLY, 0770); + if (-1 == fd) { + return false; + } + if (-1 == ftruncate(fd, length)) { + close(fd); + return false; + } + close(fd); + return true; +#endif + } + std::string get_ms_date(date_format format) { char buf[30]; diff --git a/test/test_base.cpp b/test/test_base.cpp index 5127e1d..a57de19 100644 --- a/test/test_base.cpp +++ b/test/test_base.cpp @@ -10,28 +10,28 @@ #include namespace as_test { - std::string get_random_string(size_t size) { + std::string get_random_string(size_t size) { static bool initialized = false; if (!initialized) { - srand(time(NULL)); + srand(static_cast(time(NULL))); initialized = true; } - auto randchar = []() -> char - { + auto randchar = []() -> char + { const char charset[] = - "0123456789abcdefghijklmnopqrstuvwxyz"; - const size_t max_index = (sizeof(charset) - 1); - return charset[rand() % max_index]; - }; - std::string str(size, 0); - std::generate_n(str.begin(), size, randchar); - return str; - } + "0123456789abcdefghijklmnopqrstuvwxyz"; + const size_t max_index = (sizeof(charset) - 1); + return charset[rand() % max_index]; + }; + std::string str(size, 0); + std::generate_n(str.begin(), size, randchar); + return str; + } std::istringstream get_istringstream_with_random_buffer(size_t size) { static bool initialized = false; if (!initialized) { - srand(time(NULL)); + srand(static_cast(time(NULL))); initialized = true; } auto randchar = []() -> char @@ -96,70 +96,70 @@ namespace as_test { return result; } - azure::storage_lite::blob_client& base::test_blob_client(int size) { - static std::unordered_map> bcs; - if (bcs[size] == NULL) - { + azure::storage_lite::blob_client& base::test_blob_client(int size) { + static std::unordered_map> bcs; + if (bcs[size] == NULL) + { bcs[size] = std::make_shared(azure::storage_lite::blob_client(init_account(standard_storage_connection_string()), size)); - } - return *bcs[size]; - } + } + return *bcs[size]; + } const std::shared_ptr base::init_account(const std::string& connection_string) { - auto settings = parse_string_into_settings(connection_string); - auto credential = std::make_shared(azure::storage_lite::shared_key_credential(settings["AccountName"], settings["AccountKey"])); - bool use_https = true; - if (settings["DefaultEndpointsProtocol"] == "http") - { - use_https = false; - } - std::string blob_endpoint; - if (!settings["BlobEndpoint"].empty()) - { - blob_endpoint = settings["BlobEndpoint"]; - } + auto settings = parse_string_into_settings(connection_string); + auto credential = std::make_shared(azure::storage_lite::shared_key_credential(settings["AccountName"], settings["AccountKey"])); + bool use_https = true; + if (settings["DefaultEndpointsProtocol"] == "http") + { + use_https = false; + } + std::string blob_endpoint; + if (!settings["BlobEndpoint"].empty()) + { + blob_endpoint = settings["BlobEndpoint"]; + } - return std::make_shared(azure::storage_lite::storage_account(settings["AccountName"], credential, use_https, blob_endpoint)); - } + return std::make_shared(azure::storage_lite::storage_account(settings["AccountName"], credential, use_https, blob_endpoint)); + } - std::map base::parse_string_into_settings(const std::string& connection_string) - { - std::map settings; - std::vector splitted_string; + std::map base::parse_string_into_settings(const std::string& connection_string) + { + std::map settings; + std::vector splitted_string; - // Split the connection string by ';' - { - std::istringstream iss(connection_string); - std::string s; - while (getline(iss, s, ';')) { - splitted_string.push_back(s); - } - } + // Split the connection string by ';' + { + std::istringstream iss(connection_string); + std::string s; + while (getline(iss, s, ';')) { + splitted_string.push_back(s); + } + } - for (auto iter = splitted_string.cbegin(); iter != splitted_string.cend(); ++iter) - { - if (!iter->empty()) - { - auto equals = iter->find('='); + for (auto iter = splitted_string.cbegin(); iter != splitted_string.cend(); ++iter) + { + if (!iter->empty()) + { + auto equals = iter->find('='); - std::string key = iter->substr(0, equals); - if (!key.empty()) - { - std::string value; - if (equals != std::string::npos) - { - value = iter->substr(equals + 1); - } + std::string key = iter->substr(0, equals); + if (!key.empty()) + { + std::string value; + if (equals != std::string::npos) + { + value = iter->substr(equals + 1); + } - settings.insert(std::make_pair(std::move(key), std::move(value))); - } - else - { - throw std::logic_error("The format of connection string cannot be recognized."); - } - } - } + settings.insert(std::make_pair(std::move(key), std::move(value))); + } + else + { + throw std::logic_error("The format of connection string cannot be recognized."); + } + } + } - return settings; - } + return settings; + } } diff --git a/test/test_base.h b/test/test_base.h index 90e056e..fcf09e8 100644 --- a/test/test_base.h +++ b/test/test_base.h @@ -10,17 +10,17 @@ namespace as_test { std::istringstream get_istringstream_with_random_buffer(size_t size); std::string to_base64(const char* base, size_t length); - class base { + class base { public: - static azure::storage_lite::blob_client& test_blob_client(int size = 1); + static azure::storage_lite::blob_client& test_blob_client(int size = 1); - static const std::string& standard_storage_connection_string() { - static std::string sscs = "DefaultEndpointsProtocol=https;"; - return sscs; - } + static const std::string& standard_storage_connection_string() { + static std::string sscs = "DefaultEndpointsProtocol=https;"; + return sscs; + } private: static const std::shared_ptr init_account(const std::string& connection_string); static std::map parse_string_into_settings(const std::string& connection_string); - }; + }; }