Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions include/miniocpp/args.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#ifndef MINIO_CPP_ARGS_H_INCLUDED
#define MINIO_CPP_ARGS_H_INCLUDED

#include <filesystem>
#include <functional>
#include <list>
#include <map>
Expand Down Expand Up @@ -208,7 +209,7 @@ using StatObjectArgs = ObjectConditionalReadArgs;
using RemoveObjectArgs = ObjectVersionArgs;

struct DownloadObjectArgs : public ObjectReadArgs {
std::string filename;
std::filesystem::path filename;
bool overwrite;
http::ProgressFunction progressfunc = nullptr;
void* progress_userdata = nullptr;
Expand Down Expand Up @@ -396,7 +397,7 @@ struct ComposeObjectArgs : public ObjectWriteArgs {
}; // struct ComposeObjectArgs

struct UploadObjectArgs : public PutObjectBaseArgs {
std::string filename;
std::filesystem::path filename;
http::ProgressFunction progressfunc = nullptr;
void* progress_userdata = nullptr;

Expand Down
12 changes: 12 additions & 0 deletions include/miniocpp/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#endif

#include <ctime>
#include <filesystem>
#include <ios>
#include <list>
#include <map>
Expand All @@ -38,6 +39,17 @@

namespace minio::utils {

// path::u8string() returns std::string in C++17 but std::u8string in C++20;
// normalize to std::string so callers work under both standards.
inline std::string PathToUtf8(const std::filesystem::path& p) {
#ifdef __cpp_lib_char8_t
const std::u8string u8 = p.u8string();
return std::string(reinterpret_cast<const char*>(u8.data()), u8.size());
#else
return p.u8string();
#endif
}

inline constexpr unsigned int kMaxMultipartCount = 10000; // 10000 parts
inline constexpr unsigned int kOptPartSize = 64 * 1024 * 1024; // 64MiB
inline constexpr unsigned int kMinPartSize = 5 * 1024 * 1024; // 5MiB
Expand Down
32 changes: 23 additions & 9 deletions src/args.cc
Original file line number Diff line number Diff line change
Expand Up @@ -211,12 +211,21 @@ error::Error DownloadObjectArgs::Validate() const {
if (error::Error err = ObjectReadArgs::Validate()) {
return err;
}
if (!utils::CheckNonEmptyString(filename)) {
if (!utils::CheckNonEmptyString(utils::PathToUtf8(filename))) {
return error::Error("filename cannot be empty");
}

if (!overwrite && std::filesystem::exists(filename)) {
return error::Error("file " + filename + " already exists");
if (!overwrite) {
std::error_code ec;
const bool exists = std::filesystem::exists(filename, ec);
if (ec) {
return error::Error("unable to check " + utils::PathToUtf8(filename) +
": " + ec.message());
}
if (exists) {
return error::Error("file " + utils::PathToUtf8(filename) +
" already exists");
}
}

return error::SUCCESS;
Expand Down Expand Up @@ -433,16 +442,21 @@ error::Error UploadObjectArgs::Validate() {
if (error::Error err = ObjectArgs::Validate()) {
return err;
}
if (!utils::CheckNonEmptyString(filename)) {
if (!utils::CheckNonEmptyString(utils::PathToUtf8(filename))) {
return error::Error("filename cannot be empty");
}

if (!std::filesystem::exists(filename)) {
return error::Error("file " + filename + " does not exist");
std::error_code ec;
const std::uintmax_t obj_size = std::filesystem::file_size(filename, ec);
if (ec) {
if (ec == std::errc::no_such_file_or_directory) {
return error::Error("file " + utils::PathToUtf8(filename) +
" does not exist");
}
return error::Error("unable to stat " + utils::PathToUtf8(filename) + ": " +
ec.message());
}

std::filesystem::path file_path = filename;
object_size = static_cast<uint64_t>(std::filesystem::file_size(file_path));
object_size = static_cast<uint64_t>(obj_size);
return utils::CalcPartInfo(object_size, part_size, part_count);
}

Expand Down
15 changes: 9 additions & 6 deletions src/client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1160,13 +1160,15 @@ Result<DownloadObjectResponse> Client::DownloadObject(DownloadObjectArgs args) {
etag = resp->etag;
}

std::string temp_filename =
args.filename + "." + utils::UriEncode(etag) + ".part.minio";
// Keep the temporary name a path so non-ASCII names survive on Windows
// (ofstream's path overload uses the wide API there).
std::filesystem::path temp_filename = args.filename;
temp_filename += "." + utils::UriEncode(etag) + ".part.minio";
std::ofstream fout(temp_filename,
std::ios::trunc | std::ios::out | std::ios::binary);
if (!fout.is_open()) {
return error::make<DownloadObjectResponse>("unable to open file " +
temp_filename);
return error::make<DownloadObjectResponse>(
"unable to open file " + utils::PathToUtf8(temp_filename));
}

std::string region;
Expand Down Expand Up @@ -1671,8 +1673,9 @@ Result<UploadObjectResponse> Client::UploadObject(UploadObjectArgs args) {
try {
file.open(args.filename);
} catch (std::system_error& err) {
return error::make<UploadObjectResponse>(
"unable to open file " + args.filename + "; " + err.code().message());
return error::make<UploadObjectResponse>("unable to open file " +
utils::PathToUtf8(args.filename) +
"; " + err.code().message());
}

PutObjectArgs po_args(file, args.object_size, 0);
Expand Down
Loading