11 #include <sys/types.h>
33 std::unique_ptr<ioHandle::attrDataType> attrData,
34 std::unique_ptr<acl::list> aclData) {
35 return std::unique_ptr<base::writer>(
new writerLibssh(path,
38 sourceSize, readBlockSize,
39 state, noWrite, std::move(attrData),
44 const std::string& srcPath,
46 std::vector<std::remove_reference<decltype(path)>::type::value_type> disposable_buffer(path.c_str(), path.c_str() + path.size() + 1);
47 std::string dir(dirname(disposable_buffer.data()));
50 auto stat =
getUniquePtr(sftp_stat(
sftp, dir.c_str()), sftp_attributes_free);
53 if (stat ==
nullptr) {
54 if (sftp_get_error(
sftp) == SSH_FX_NO_SUCH_FILE) {
58 auto result = sftp_mkdir(
sftp, dir.c_str(), 0777u);
60 if (result != 0 && sftp_get_error(
sftp) == SSH_FX_FILE_ALREADY_EXISTS) {
66 if (
gid != -1 ||
uid != -1) {
69 "can't set owner/group (",
uid,
",",
gid,
") on ", dir);
72 }
else if (stat->type != SSH_FILEXFER_TYPE_DIRECTORY) {
74 dir,
"ensure parents",
75 "is not a directory (st_mode is ",
76 static_cast<int>(stat->type),
77 ", perm: ", std::hex, stat->permissions,
84 auto stat =
getUniquePtr(sftp_lstat(
sftp, path.c_str()), sftp_attributes_free);
85 if (stat ==
nullptr && sftp_get_error(
sftp) == SSH_FX_NO_SUCH_FILE) {
89 if (stat->type == SSH_FILEXFER_TYPE_DIRECTORY) {
90 auto retval = sftp_rmdir(
sftp, path.c_str());
92 switch (sftp_get_error(
sftp)) {
93 case SSH_FX_NO_SUCH_FILE:
96 case SSH_FX_FILE_ALREADY_EXISTS:
98 path,
"remove",
"directory not empty but should be removed");
108 auto retval = sftp_unlink(
sftp, path.c_str());
110 if (retval && sftp_get_error(
sftp) == SSH_FX_NO_SUCH_FILE) {
120 const std::string& toPath) {
122 auto retval = sftp_unlink(
sftp, toPath.c_str());
123 if (retval && sftp_get_error(
sftp) == SSH_FX_NO_SUCH_FILE) {
125 toPath,
"unlink in renameSimple",
131 auto retval = sftp_rename(
sftp, fromPath.c_str(), toPath.c_str());
132 if (retval && (sftp_get_error(
sftp) == SSH_FX_NO_SUCH_FILE)) {
141 const std::unique_ptr<const genericStat>& readInitialStat,
142 const std::string& toPath,
145 sftp_attributes_free);
146 if (fromPathStatBuf ==
nullptr && sftp_get_error(
sftp) == SSH_FX_NO_SUCH_FILE) {
147 if (readInitialStat && readInitialStat->
isDir()) {
153 }
else if (fromPathStatBuf ==
nullptr) {
158 if (!readInitialStat || (! readInitialStat->
isDir() &&
159 (fromPathStat.
size != readInitialStat->
size
162 if (readInitialStat) {
163 std::string initialTime;
164 std::string finalTime;
165 readInitialStat->
getMtime(initialTime);
169 "file (", toPath,
") changed unexpectedly ("
170 , initialTime,
" -> ", finalTime,
", "
171 , readInitialStat->
size,
" -> ", fromPathStat.
size
172 ,
", doing fresh copy");
176 "file (", toPath,
") has no initial stat, doing fresh copy");
180 auto retval = sftp_rename(
sftp, fromPath.c_str(), toPath.c_str());
182 if (retval && (errno == ENOENT || errno == ENOTDIR)) {
183 if (readInitialStat->
isDir()) {
189 "vanished unexpectedly, doing fresh copy");
193 throwcall::good0(retval,
"can't rename '", fromPath,
"' to '", toPath,
"'");
202 const std::string& path,
206 auto retval = sftp_symlink(
sftp, target.data(), path.c_str());
207 if (retval != 0 && sftp_get_error(
sftp) != SSH_FX_FILE_ALREADY_EXISTS) {
211 if (
static_cast<std::make_signed<decltype(
gid)
>::type>(
gid) != -1
212 ||
static_cast<std::make_signed<decltype(
uid)
>::type>(
uid) != -1) {
215 "can't set owner/group (",
uid,
",",
gid,
") on ", path);
224 size_t readBlockSize,
227 std::unique_ptr<ioHandle::attrDataType> aAttrData,
228 std::unique_ptr<acl::list> ):
230 writeInitialStat(nullptr),
231 attrData(std::move(aAttrData)) {
236 auto openMode = O_CREAT | O_TRUNC | O_WRONLY;
241 if (sftp_get_error(
handler.
sftp) != SSH_FX_NO_SUCH_FILE) {
246 sourceSize > readBlockSize) {
256 "can't open ",
path,
" for writing");
262 "can't stat destination file ",
path);
271 if (sftp_close(file) == SSH_ERROR) {
273 path,
"close during unwind ",
274 "sftp error ", sftp_get_error(handler.sftp),
275 ", ssh error ", ssh_get_error(handler.session));
279 path,
"unlink failed copy",
"due to exception");
281 auto retval = sftp_unlink(handler.sftp, path.c_str());
282 if (retval && sftp_get_error(handler.sftp) != SSH_FX_NO_SUCH_FILE) {
284 path,
"can't remove bad copy ",
285 "sftp error ", sftp_get_error(handler.sftp),
286 ", ssh error ", ssh_get_error(handler.session));
291 if (writeInitialStat !=
nullptr) {
292 sftp_attributes_free(writeInitialStat);
294 if (file !=
nullptr) {
296 closeAndRemoveBadCopy();
302 }
catch (
const std::exception& e) {
304 path,
"set attr at close ",
306 closeAndRemoveBadCopy();
318 "can't seek ", path,
" to ", position);
321 return writeInitialStat->size;
326 auto currentPosition = sftp_tell64(file);
327 auto holeEnd = currentPosition + b.
size();
329 "can't seek to hole end (", holeEnd,
") in ", path);
333 size_t bytes_writen_so_far = 0;
335 while (bytes_writen_so_far < b.
size()) {
336 auto count = b.
size() - bytes_writen_so_far;
338 if (count > blockSize) {
343 auto bytes_writen = sftp_write(file, b.
bufferAt(bytes_writen_so_far), count);
344 if (bytes_writen < 0) {
348 bytes_writen_so_far += bytes_writen;
355 struct timeval times[2];
360 "can't set time stamp of ", path);
366 "can't set mode of ", path);
368 auto oldmask = umask(0);
371 "can't set mode of ", path);
375 if (
gid != -1 ||
uid != -1) {
378 "can't set owner/group (",
uid,
",",
gid,
") of ", path);
384 "can't set owner/group (", readInitialStat.
ownerUid,
",", readInitialStat.
ownerGid,
") of ",
392 #if LIBSFTP_VERSION > 3
394 "can't sync ", path);
400 if (stat.f_namemax > 0) {
401 return stat.f_namemax;