19 std::unique_ptr<ioHandle::attrDataType>,
20 std::unique_ptr<acl::list> aclData) {
21 return std::unique_ptr<base::writer>(
new writerDcap(path, mightAppend,
22 sourceSize, readBlockSize,
30 "--",
"dcap output handler",
31 "setting setAttributesAfterClose automatically");
37 const std::string& srcPath,
39 std::vector<std::remove_reference<decltype(path)>::type::value_type> disposable_buffer(path.c_str(), path.c_str() + path.size() + 1);
40 std::string dir(dirname(disposable_buffer.data()));
45 statResult = dc_stat(
fixPathUrl(dir).c_str(), &statbuf);
48 if (errno == ENOENT) {
49 auto srcDir = srcPath.substr(0, srcPath.find_last_of(
'/'));
50 while (srcDir.back() ==
'/') {
56 auto aclData = InputHandler->
getAclData(srcDir);
61 auto result = dc_mkdir(
fixPathUrl(dir).c_str(), 0777u);
63 if (result != 0 && errno == EEXIST) {
69 if (
gid != -1 ||
uid != -1) {
73 }
else if (! S_ISDIR(statbuf.st_mode)) {
75 dir,
"ensure parents",
76 "is not a directory (st_mode is ", statbuf.st_mode,
") but should be");
85 auto retval = dc_lstat(
fixPathUrl(path).c_str(), &dsttat);
87 if (retval && errno == ENOENT) {
92 if (S_ISDIR(dsttat.st_mode)) {
93 auto retval = dc_rmdir(
fixPathUrl(path).c_str());
102 path,
"remove",
"directory not empty but should be removed");
112 auto retval = dc_unlink(
fixPathUrl(path).c_str());
114 if (retval && errno == ENOENT) {
125 const std::string& toPath) {
127 auto retval = dc_rename(fromPath.c_str(), toPath.c_str());
137 const std::unique_ptr<const genericStat>& readInitialStat,
138 const std::string& toPath,
142 auto statRetVal = dc_stat(
fixPathUrl(fromPath).c_str(), &fromPathStatBuf);
143 if (statRetVal && (errno == ENOENT || errno == ENOTDIR)) {
144 if (readInitialStat && readInitialStat->
isDir()) {
150 }
else if (statRetVal) {
154 genericStat fromPathStat(fromPathStatBuf, std::chrono::seconds(1));
155 if (! readInitialStat || (
156 ! readInitialStat->
isDir() &&
157 (fromPathStat.
size != readInitialStat->
size
162 "file (", toPath,
") changed unexpectedly, doing fresh copy");
167 if (retval && (errno == ENOENT || errno == ENOTDIR)) {
168 if (readInitialStat->
isDir()) {
174 "vanished unexpectedly, doing fresh copy");
192 bool needSpace =
false;
193 std::string result(
" -acl=\"");
194 for (
const auto& entry : aclData.
entries) {
199 result += entry.isAllowedType() ?
"A:" :
"D:";
204 switch (entry.e_id) {
205 case acl::list::entryType::specialIdType::owner_special_id:
208 case acl::list::entryType::specialIdType::group_special_id:
211 case acl::list::entryType::specialIdType::everyone_special_id:
212 result +=
"EVERYONE@:";
215 throw std::runtime_error(
"illegal special id");
218 result += std::to_string(entry.e_id);
222 auto mask = entry._mask;
226 if (mask & item.first) {
227 result += item.second;
232 dc_setExtraOption(
const_cast<char*
>(result.c_str()));
241 "enable unsafe write mode, i.e. check only at close()");
243 "disable dcap-internal adler32 checksum");
252 std::unique_ptr<acl::list> aclData):
259 std::string
options(
"-alloc-size=");
260 options += std::to_string(sourceSize);
261 dc_setExtraOption(
const_cast<char*
>(
options.c_str()));
265 auto openMode = O_CREAT | O_TRUNC | O_WRONLY;
269 -1,
"can't open ",
path,
" for writing");
279 if (dc_close(fd) != 0) {
281 path,
"close during unwind ",
282 dc_strerror(dc_errno));
285 path,
"unlink failed copy",
"due to exception");
286 if (dc_unlink(path.c_str()) != 0) {
288 path,
"can't remove bad copy ",
289 dc_strerror(dc_errno));
297 closeAndRemoveBadCopy();
306 size_t bytes_writen_so_far = 0;
308 while (bytes_writen_so_far < b.
size()) {
310 auto count = b.
size() - bytes_writen_so_far;
315 count = std::min(count, blockSize);
318 -1,
"write failed on ", path);
319 if (bytes_writen == 0) {
320 throw std::runtime_error(
"wrote 0 bytes for " + path);
323 bytes_writen_so_far += bytes_writen;
334 struct timespec times[2];
335 times[0].tv_nsec = UTIME_OMIT;
337 auto serverStart = path.find(
"://");
338 if (serverStart == std::string::npos) {
339 throw std::runtime_error(path +
" contains no \"://\"");
341 auto realPathStart = path.find(
"/", serverStart + 3);
342 if (realPathStart == std::string::npos) {
343 throw std::runtime_error(path +
" contains no path after server part");
347 "can't set mtime on ", path.c_str() + realPathStart);
353 auto oldmask = umask(0);
354 auto retval = dc_chmod(path.c_str(),
modeBits & ~oldmask);
357 path,
"chmod",
"can't set mode ", dc_errno,
" (", dc_strerror(dc_errno),
") ");
363 if (
gid != -1 ||
uid != -1) {