summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRyo Nakamura <upa@haeena.net>2023-08-04 15:06:14 +0900
committerRyo Nakamura <upa@haeena.net>2023-08-04 15:06:14 +0900
commit24c1bc9149eb8f1c383eaf16d94636b62d07c152 (patch)
tree54dd5823cb8255a493a851e4ecec74aeae675370 /src
parent16f2f88cc91ffa2421393b077611d55d6cd2b771 (diff)
do not set O_TRUNC when opening destination file.
It prevents `mscp localhost:hoge ~/hoge` from truncating the source file. See https://bugzilla.mindrot.org/show_bug.cgi?id=3431. https://github.com/upa/mscp/issues/1
Diffstat (limited to 'src')
-rw-r--r--src/fileops.c17
-rw-r--r--src/fileops.h6
-rw-r--r--src/path.c9
3 files changed, 24 insertions, 8 deletions
diff --git a/src/fileops.c b/src/fileops.c
index 994dd77..d9587ef 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -293,15 +293,24 @@ int mscp_lseek(mf *f, size_t off)
return ret;
}
-int mscp_chmod(const char *path, mode_t mode, sftp_session sftp)
+int mscp_setstat(const char *path, mode_t mode, size_t size, sftp_session sftp)
{
int ret;
if (sftp) {
- ret = sftp_chmod(sftp, path, mode);
+ struct sftp_attributes_struct attr;
+ memset(&attr, 0, sizeof(attr));
+ attr.permissions = mode;
+ attr.size = size;
+ attr.flags = (SSH_FILEXFER_ATTR_PERMISSIONS|SSH_FILEXFER_ATTR_SIZE);
+ ret = sftp_setstat(sftp, path, &attr);
sftp_err_to_errno(sftp);
- } else
- ret = chmod(path, mode);
+ } else {
+ if ((ret = chmod(path, mode)) < 0)
+ return ret;
+ if ((ret = truncate(path, size)) < 0)
+ return ret;
+ }
return ret;
}
diff --git a/src/fileops.h b/src/fileops.h
index ede9c48..8dc6e5b 100644
--- a/src/fileops.h
+++ b/src/fileops.h
@@ -46,7 +46,11 @@ typedef struct mf_struct mf;
mf *mscp_open(const char *path, int flags, mode_t mode, sftp_session sftp);
void mscp_close(mf *f);
int mscp_lseek(mf *f, size_t off);
-int mscp_chmod(const char *path, mode_t mode, sftp_session sftp);
+
+/* mscp_setstat() involves chmod and truncate. It executes both at
+ * once via a single SFTP command (sftp_setstat()).
+ */
+int mscp_setstat(const char *path, mode_t mode, size_t size, sftp_session sftp);
/* remote glob */
int mscp_glob(const char *pattern, int flags, glob_t *pglob, sftp_session sftp);
diff --git a/src/path.c b/src/path.c
index e35ff06..254f8c3 100644
--- a/src/path.c
+++ b/src/path.c
@@ -334,8 +334,9 @@ static int touch_dst_path(struct path *p, sftp_session sftp)
*needle = '/';
}
- /* open file with O_TRUNC to set file size 0 */
- f = mscp_open(p->dst_path, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR, sftp);
+ /* Do not set O_TRUNC here. Instead, do mscp_setstat() at the
+ * end. see https://bugzilla.mindrot.org/show_bug.cgi?id=3431 */
+ f = mscp_open(p->dst_path, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR, sftp);
if (!f) {
mscp_set_error("mscp_open %s: %s\n", p->dst_path, strerrno());
return -1;
@@ -574,7 +575,9 @@ int copy_chunk(FILE *msg_fp, struct chunk *c,
if (refcnt_dec(&c->p->refcnt) == 0) {
c->p->state = FILE_STATE_DONE;
- mscp_chmod(c->p->dst_path, c->p->mode, dst_sftp);
+ if (mscp_setstat(c->p->dst_path, c->p->mode, c->p->size, dst_sftp) < 0)
+ mpr_err(msg_fp, "failed to chmod and truncate %s: %s\n",
+ c->p->path, strerrno());
mpr_info(msg_fp, "copy done: %s\n", c->p->path);
}