#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include "distcc.h"
#include "trace.h"
#include "util.h"
#include "rpc.h"
#include "exitcode.h"
#include "dopt.h"
#include "hosts.h"
#include "bulk.h"
#include "snprintf.h"
#ifdef XCODE_INTEGRATION
# include "xci.h"
#endif
int dcc_r_request_header(int ifd,
enum dcc_protover *ver_ret)
{
unsigned vers;
int ret;
if ((ret = dcc_r_token_int(ifd, "DIST", &vers)) != 0) {
rs_log_error("client did not provide distcc magic fairy dust");
return ret;
}
if (vers > DCC_VER_3) {
rs_log_error("can't handle requested protocol version is %d", vers);
return EXIT_PROTOCOL_ERROR;
}
*ver_ret = (enum dcc_protover) vers;
return 0;
}
int dcc_r_cwd(int ifd, char **cwd)
{
return dcc_r_token_string(ifd, "CDIR", cwd);
}
static int prepend_dir_to_name(const char *dirname, char **path)
{
char *buf;
asprintf(&buf, "%s%s", dirname, *path);
if (buf == NULL) {
return EXIT_OUT_OF_MEMORY;
}
free(*path);
*path = buf;
return 0;
}
int dcc_r_many_files(int in_fd,
const char *dirname,
enum dcc_compress compr)
{
int ret = 0;
unsigned int n_files;
unsigned int i;
char *name = NULL;
char *link_target = NULL;
char token[5];
#ifdef XCODE_INTEGRATION
char *xci_name, *xci_link_target, *extension;
#endif
if ((ret = dcc_r_token_int(in_fd, "NFIL", &n_files)))
return ret;
for (i = 0; i < n_files; ++i) {
unsigned int link_or_file_len;
if ((ret = dcc_r_token_string(in_fd, "NAME", &name)))
goto out_cleanup;
#ifdef XCODE_INTEGRATION
xci_name = dcc_xci_unmask_developer_dir(name);
if (xci_name) {
free(name);
name = xci_name;
xci_name = NULL;
} else {
ret = EXIT_OUT_OF_MEMORY;
goto out_cleanup;
}
#endif
if ((ret = prepend_dir_to_name(dirname, &name)))
goto out_cleanup;
if ((ret = dcc_r_sometoken_int(in_fd, token, &link_or_file_len)))
goto out_cleanup;
if (strncmp(token, "LINK", 4) == 0) {
if ((ret = dcc_r_str_alloc(in_fd, link_or_file_len, &link_target))){
goto out_cleanup;
}
rs_trace("got '%s'", link_target);
#ifdef XCODE_INTEGRATION
xci_link_target = dcc_xci_unmask_developer_dir(link_target);
if (xci_link_target) {
free(link_target);
link_target = xci_link_target;
xci_link_target = NULL;
} else {
ret = EXIT_OUT_OF_MEMORY;
goto out_cleanup;
}
#endif
if (link_target[0] == '/') {
if ((ret = prepend_dir_to_name(dirname, &link_target))) {
goto out_cleanup;
}
}
if ((ret = dcc_mk_tmp_ancestor_dirs(name))) {
goto out_cleanup;
}
if (symlink(link_target, name) != 0) {
rs_log_error("failed to create path for %s: %s", name,
strerror(errno));
ret = 1;
goto out_cleanup;
}
if ((ret = dcc_add_cleanup(name))) {
unlink(name);
goto out_cleanup;
}
} else if (strncmp(token, "FILE", 4) == 0) {
if ((ret = dcc_r_file(in_fd, name, link_or_file_len, compr))) {
goto out_cleanup;
}
#ifdef XCODE_INTEGRATION
if ((extension = dcc_find_extension(name))
&& !strcmp(extension, ".hmap")
&& (ret = dcc_xci_headermap_fix(name, dirname))) {
unlink(name);
goto out_cleanup;
}
#endif
if ((ret = dcc_add_cleanup(name))) {
unlink(name);
goto out_cleanup;
}
} else {
char buf[4 + sizeof(link_or_file_len)];
rs_log_error("protocol derailment: expected token FILE or LINK");
strncpy(buf, token, 4);
memcpy(&buf[4], &link_or_file_len, sizeof(link_or_file_len));
dcc_explain_mismatch(buf, 12, in_fd);
ret = EXIT_PROTOCOL_ERROR;
goto out_cleanup;
}
out_cleanup:
if (name) {
free(name);
name = NULL;
}
if (link_target) {
free(link_target);
link_target = NULL;
}
if (ret)
break;
}
return ret;
}