Skip to content

Commit e436c67

Browse files
authored
Merge pull request #5666 from larsewi/atomic
ENT-12511: Now `cf-net get` no longer unlinks original file
2 parents bea1391 + cc12344 commit e436c67

File tree

2 files changed

+79
-80
lines changed

2 files changed

+79
-80
lines changed

libcfnet/file_stream.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,7 @@ static bool RecvDelta(
853853
char in_buf[PROTOCOL_MESSAGE_SIZE * 2], out_buf[PROTOCOL_MESSAGE_SIZE];
854854

855855
/* Open/create the destination file */
856+
unlink(dest);
856857
int new = safe_open_create_perms(
857858
dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL | O_BINARY, perms);
858859
if (new == -1)

libcfnet/protocol.c

Lines changed: 78 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,11 @@ bool ProtocolGet(AgentConnection *conn, const char *remote_path,
101101

102102
perms = (perms == 0) ? CF_PERMS_DEFAULT : perms;
103103

104-
unlink(local_path);
105-
FILE *file_ptr = safe_fopen_create_perms(local_path, "wx", perms);
106-
if (file_ptr == NULL)
104+
char dest[PATH_MAX];
105+
int ret = snprintf(dest, sizeof(dest), "%s.cfnew", local_path);
106+
if (ret < 0 || (size_t)ret >= sizeof(dest))
107107
{
108-
Log(LOG_LEVEL_WARNING, "Failed to open file %s (fopen: %s)",
109-
local_path, GetErrorStr());
108+
Log(LOG_LEVEL_ERR, "Truncation error: Path too long (%d >= %zu)", ret, sizeof(dest));
110109
return false;
111110
}
112111

@@ -115,112 +114,111 @@ bool ProtocolGet(AgentConnection *conn, const char *remote_path,
115114
CF_MSGSIZE, remote_path);
116115

117116

118-
int ret = SendTransaction(conn->conn_info, buf, to_send, CF_DONE);
117+
ret = SendTransaction(conn->conn_info, buf, to_send, CF_DONE);
119118
if (ret == -1)
120119
{
121120
Log(LOG_LEVEL_WARNING, "Failed to send request for remote file %s:%s",
122121
conn->this_server, remote_path);
123-
unlink(local_path);
124-
fclose(file_ptr);
125122
return false;
126123
}
127124

128-
/* Use file stream API if it is available */
125+
bool success = true;
126+
129127
const ProtocolVersion version = ConnectionInfoProtocolVersion(conn->conn_info);
130128
if (ProtocolSupportsFileStream(version))
131129
{
132-
fclose(file_ptr);
133-
134-
char dest[PATH_MAX];
135-
ret = snprintf(dest, sizeof(dest), "%s.cfnew", local_path);
136-
if (ret < 0 || (size_t)ret >= sizeof(dest))
137-
{
138-
Log(LOG_LEVEL_ERR, "Truncation error: Path too long (%d >= %zu)", ret, sizeof(dest));
139-
return false;
140-
}
141-
130+
/* Use file stream API if it is available */
142131
if (!FileStreamFetch(conn->conn_info->ssl, local_path, dest, perms))
143132
{
144133
/* Error is already logged */
145-
return false;
134+
success = false;
146135
}
147-
148-
Log(LOG_LEVEL_VERBOSE, "Replacing file '%s' with '%s'...", dest, local_path);
149-
if (rename(dest, local_path) == -1)
136+
}
137+
else {
138+
/* Otherwise, use older protocol */
139+
unlink(dest);
140+
FILE *file_ptr = safe_fopen_create_perms(dest, "wx", perms);
141+
if (file_ptr == NULL)
150142
{
151-
Log(LOG_LEVEL_ERR, "Failed to replace destination file '%s' with basis file '%s': %s", dest, local_path, GetErrorStr());
143+
Log(LOG_LEVEL_WARNING, "Failed to open file %s (fopen: %s)",
144+
dest, GetErrorStr());
152145
return false;
153146
}
154147

155-
return true;
156-
}
157-
158-
/* Otherwise, use old protocol */
148+
char cfchangedstr[sizeof(CF_CHANGEDSTR1 CF_CHANGEDSTR2)];
149+
snprintf(cfchangedstr, sizeof(cfchangedstr), "%s%s",
150+
CF_CHANGEDSTR1, CF_CHANGEDSTR2);
159151

160-
char cfchangedstr[sizeof(CF_CHANGEDSTR1 CF_CHANGEDSTR2)];
161-
snprintf(cfchangedstr, sizeof(cfchangedstr), "%s%s",
162-
CF_CHANGEDSTR1, CF_CHANGEDSTR2);
163-
164-
bool success = true;
165-
uint32_t received_bytes = 0;
166-
while (received_bytes < file_size)
167-
{
168-
int len = TLSRecv(conn->conn_info->ssl, buf, CF_MSGSIZE);
169-
if (len == -1)
170-
{
171-
Log(LOG_LEVEL_WARNING, "Failed to GET file %s:%s",
172-
conn->this_server, remote_path);
173-
success = false;
174-
break;
175-
}
176-
else if (len > CF_MSGSIZE)
152+
uint32_t received_bytes = 0;
153+
while (received_bytes < file_size)
177154
{
178-
Log(LOG_LEVEL_WARNING,
179-
"Incorrect length of incoming packet "
180-
"while retrieving %s:%s, %d > %d",
181-
conn->this_server, remote_path, len, CF_MSGSIZE);
182-
success = false;
183-
break;
184-
}
155+
int len = TLSRecv(conn->conn_info->ssl, buf, CF_MSGSIZE);
156+
if (len == -1)
157+
{
158+
Log(LOG_LEVEL_WARNING, "Failed to GET file %s:%s",
159+
conn->this_server, remote_path);
160+
success = false;
161+
break;
162+
}
163+
else if (len > CF_MSGSIZE)
164+
{
165+
Log(LOG_LEVEL_WARNING,
166+
"Incorrect length of incoming packet "
167+
"while retrieving %s:%s, %d > %d",
168+
conn->this_server, remote_path, len, CF_MSGSIZE);
169+
success = false;
170+
break;
171+
}
185172

186-
if (BadProtoReply(buf))
187-
{
188-
Log(LOG_LEVEL_ERR,
189-
"Error from server while retrieving file %s:%s: %s",
190-
conn->this_server, remote_path, buf);
191-
success = false;
192-
break;
193-
}
173+
if (BadProtoReply(buf))
174+
{
175+
Log(LOG_LEVEL_ERR,
176+
"Error from server while retrieving file %s:%s: %s",
177+
conn->this_server, remote_path, buf);
178+
success = false;
179+
break;
180+
}
194181

195-
if (StringEqualN(buf, cfchangedstr, sizeof(cfchangedstr) - 1))
196-
{
197-
Log(LOG_LEVEL_ERR,
198-
"Remote file %s:%s changed during file transfer",
199-
conn->this_server, remote_path);
200-
success = false;
201-
break;
202-
}
182+
if (StringEqualN(buf, cfchangedstr, sizeof(cfchangedstr) - 1))
183+
{
184+
Log(LOG_LEVEL_ERR,
185+
"Remote file %s:%s changed during file transfer",
186+
conn->this_server, remote_path);
187+
success = false;
188+
break;
189+
}
203190

204-
ret = fwrite(buf, sizeof(char), len, file_ptr);
205-
if (ret < 0)
206-
{
207-
Log(LOG_LEVEL_ERR,
208-
"Failed to write during retrieval of file %s:%s (fwrite: %s)",
209-
conn->this_server, remote_path, GetErrorStr());
210-
success = false;
211-
break;
191+
ret = fwrite(buf, sizeof(char), len, file_ptr);
192+
if (ret < 0)
193+
{
194+
Log(LOG_LEVEL_ERR,
195+
"Failed to write during retrieval of file %s:%s (fwrite: %s)",
196+
conn->this_server, remote_path, GetErrorStr());
197+
success = false;
198+
break;
199+
}
200+
201+
received_bytes += len;
212202
}
213203

214-
received_bytes += len;
204+
fclose(file_ptr);
215205
}
216206

217207
if (!success)
218208
{
219-
unlink(local_path);
209+
Log(LOG_LEVEL_VERBOSE, "Removing file '%s'...", dest);
210+
unlink(dest);
211+
return false;
220212
}
221213

222-
fclose(file_ptr);
223-
return success;
214+
Log(LOG_LEVEL_VERBOSE, "Replacing file '%s' with '%s'...", dest, local_path);
215+
if (rename(dest, local_path) == -1)
216+
{
217+
Log(LOG_LEVEL_ERR, "Failed to replace destination file '%s' with basis file '%s': %s", dest, local_path, GetErrorStr());
218+
return false;
219+
}
220+
221+
return true;
224222
}
225223

226224
bool ProtocolStatGet(AgentConnection *conn, const char *remote_path,

0 commit comments

Comments
 (0)