Added support for Windows
This commit is contained in:
Родитель
710c46315b
Коммит
983420cc8f
|
@ -52,9 +52,13 @@ dkms.conf
|
|||
|
||||
# Cmake
|
||||
build
|
||||
build.release
|
||||
|
||||
# VS folder
|
||||
.vs/
|
||||
|
||||
# Git
|
||||
*.orig
|
||||
|
||||
# Test framework
|
||||
test/catch2
|
146
CMakeLists.txt
146
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)
|
||||
|
|
|
@ -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}"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
128
README.md
128
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 `<path to OpenSSL>` should be the absolute path constructed in curl directory as dependency when building curl, normally it should be `<CURL_ROOT_PATH>\deps`. Also, `<CURL_ROOT_PATH>` 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="<path to curl>" -DOPENSSL_ROOT_DIR="<path to OpenSSL>"
|
||||
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="<path to curl libraries>" -DCURL_INCLUDE_DIRS="<path to curl include folder>" -DOPENSSL_SSL_LIBRARY="<path to OpenSSL's ssl library>" -DOPENSSL_CRYPTO_LIBRARY="<path to OpenSSL's crypto library>" -DOPENSSL_INCLUDE_DIR="<path to OpenSSL's include folder>"
|
||||
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.*
|
||||
|
|
|
@ -3,10 +3,6 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#include <bcrypt.h>
|
||||
#else
|
||||
#ifdef USE_OPENSSL
|
||||
#include <openssl/hmac.h>
|
||||
#else
|
||||
|
@ -14,54 +10,9 @@
|
|||
#include <gnutls/crypto.h>
|
||||
#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<typename Hash_Provider>
|
||||
class hash_provider_base
|
||||
{
|
||||
static std::string hash_impl(const std::string &input, const std::vector<unsigned char> &key) = delete;
|
||||
public:
|
||||
static std::string hash(const std::string &input, const std::vector<unsigned char> &key
|
||||
{
|
||||
return Hash_Provider::hash_impl(input, key);
|
||||
}
|
||||
};
|
||||
|
||||
class hmac_sha256_hash_provider : public hash_provider_base<hmac_sha256_hash_provider>
|
||||
{
|
||||
static hmac_sha256_hash_algorithm _algorithm;
|
||||
public:
|
||||
AZURE_STORAGE_API static std::string hash_impl(const std::string &input, const std::vector<unsigned char> &key);
|
||||
};
|
||||
#else
|
||||
std::string hash(const std::string &to_sign, const std::vector<unsigned char> &key);
|
||||
#endif
|
||||
|
||||
AZURE_STORAGE_API std::string hash(const std::string &to_sign, const std::vector<unsigned char> &key);
|
||||
}} // azure::storage_lite
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Rpc.h>
|
||||
#pragma warning(disable : 4996)
|
||||
#define _SNPRINTF _snprintf
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#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<typename ... Args>
|
||||
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<char[]> 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<void(log_level, const std::string&)>& new_logger)
|
||||
{
|
||||
s_logger = new_logger;
|
||||
}
|
||||
|
||||
protected:
|
||||
static std::function<void(log_level, const std::string&)> s_logger;
|
||||
|
||||
static void simple_logger(log_level level, const std::string& msg);
|
||||
};
|
||||
}}
|
|
@ -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")
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
#ifdef _WIN32
|
||||
#define AZURE_STORAGE_API __declspec(dllexport)
|
||||
#else /* ifdef WIN32 */
|
||||
#else /* ifdef _WIN32 */
|
||||
#define AZURE_STORAGE_API
|
||||
#endif
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <BaseTsd.h>
|
||||
typedef SSIZE_T ssize_t;
|
||||
#endif
|
||||
|
||||
#include "blob/blob_client.h"
|
||||
|
||||
#include "blob/download_blob_request.h"
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
/* C++ interface wrapper for blob client
|
||||
* No exceptions will throw.
|
||||
*/
|
||||
#include <sys/stat.h>
|
||||
#ifdef __linux__
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <Rpc.h>
|
||||
#endif //__linux__
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#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<list_containers_item>();
|
||||
}
|
||||
|
@ -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<size_t>(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<unsigned long long>(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")
|
||||
|
|
53
src/hash.cpp
53
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<unsigned char> &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<UCHAR> 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<UCHAR> 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<unsigned char> &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<int>(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<unsigned char>(digest, digest + l));
|
||||
}
|
||||
#endif
|
||||
|
||||
}} // azure::storage_lite
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
#include "logging.h"
|
||||
|
||||
namespace azure { namespace storage_lite {
|
||||
|
||||
std::function<void(log_level, const std::string&)> 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
|
||||
}}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,24 +4,65 @@
|
|||
|
||||
#include "constants.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <filesystem>
|
||||
#else
|
||||
#include <uuid/uuid.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#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<RPC_CSTR*>(uuid_cstr));
|
||||
res = std::string(uuid_cstr);
|
||||
RpcStringFreeA(reinterpret_cast<RPC_CSTR*>(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<uintmax_t>(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];
|
||||
|
|
|
@ -10,28 +10,28 @@
|
|||
#include <vector>
|
||||
|
||||
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<unsigned int>(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<unsigned int>(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<int, std::shared_ptr<azure::storage_lite::blob_client>> bcs;
|
||||
if (bcs[size] == NULL)
|
||||
{
|
||||
azure::storage_lite::blob_client& base::test_blob_client(int size) {
|
||||
static std::unordered_map<int, std::shared_ptr<azure::storage_lite::blob_client>> bcs;
|
||||
if (bcs[size] == NULL)
|
||||
{
|
||||
bcs[size] = std::make_shared<azure::storage_lite::blob_client>(azure::storage_lite::blob_client(init_account(standard_storage_connection_string()), size));
|
||||
}
|
||||
return *bcs[size];
|
||||
}
|
||||
}
|
||||
return *bcs[size];
|
||||
}
|
||||
|
||||
const std::shared_ptr<azure::storage_lite::storage_account> 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>(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>(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>(azure::storage_lite::storage_account(settings["AccountName"], credential, use_https, blob_endpoint));
|
||||
}
|
||||
return std::make_shared<azure::storage_lite::storage_account>(azure::storage_lite::storage_account(settings["AccountName"], credential, use_https, blob_endpoint));
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> base::parse_string_into_settings(const std::string& connection_string)
|
||||
{
|
||||
std::map<std::string, std::string> settings;
|
||||
std::vector<std::string> splitted_string;
|
||||
std::map<std::string, std::string> base::parse_string_into_settings(const std::string& connection_string)
|
||||
{
|
||||
std::map<std::string, std::string> settings;
|
||||
std::vector<std::string> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<azure::storage_lite::storage_account> init_account(const std::string& connection_string);
|
||||
static std::map<std::string, std::string> parse_string_into_settings(const std::string& connection_string);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче