/*
* Software Updater - server side
*
* Copyright © 2012-2016 Intel Corporation.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 or later of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors:
* Arjan van de Ven
*
*/
#define _GNU_SOURCE
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "swupd.h"
#include "xattrs.h"
void __create_delta(struct file *file, int from_version, char *from_hash)
{
char *original, *newfile, *outfile, *dotfile, *testnewfile, *conf;
int ret;
if (!file->is_file || !file->peer->is_file) {
return; /* only support deltas between two regular files right now */
}
if (file->is_deleted) {
return; /* file got deleted -> by definition we cannot make a delta */
}
if (file->is_dir) {
return; /* cannot do this for directories yet */
}
conf = config_image_base();
string_or_die(&newfile, "%s/%i/full/%s", conf, file->last_change, file->filename);
string_or_die(&original, "%s/%i/full/%s", conf, from_version, file->peer->filename);
free(conf);
conf = config_output_dir();
string_or_die(&outfile, "%s/%i/delta/%i-%i-%s-%s", conf, file->last_change, from_version, file->last_change, from_hash, file->hash);
string_or_die(&dotfile, "%s/%i/delta/.%i-%i-%s-%s", conf, file->last_change, from_version, file->last_change, from_hash, file->hash);
string_or_die(&testnewfile, "%s/%i/delta/.%i-%i-%s-%s.testnewfile", conf, file->last_change, from_version, file->last_change, from_hash, file->hash);
LOG(file, "Making delta", "%s->%s", original, newfile);
ret = xattrs_compare(original, newfile);
if (ret != 0) {
LOG(NULL, "xattrs have changed, don't create diff ", "%s", newfile);
goto out;
}
ret = make_bsdiff_delta(original, newfile, dotfile, 0);
if (ret < 0) {
LOG(file, "Delta creation failed", "%s->%s ret is %i", original, newfile, ret);
goto out;
}
if (ret == 1) {
LOG(file, "...delta larger than newfile: FULLDL", "%s", newfile);
unlink(dotfile);
goto out;
}
/* does delta properly recreate expected content? */
ret = apply_bsdiff_delta(original, testnewfile, dotfile);
if (ret != 0) {
printf("Delta application failed.\n");
printf("Attempted %s->%s via diff %s\n", original, testnewfile, dotfile);
LOG(file, "Delta application failed.", "Attempted %s->%s via diff %s", original, testnewfile, dotfile);
#warning the above is racy..tolerate it temporarily
// ok fine
//unlink(testnewfile);
//unlink(dotfile);
ret = 0;
goto out;
}
xattrs_copy(original, testnewfile);
/* does xattrs have been correctly copied?*/
if (xattrs_compare(original, testnewfile) != 0) {
printf("Delta application resulted in xattrs mismatch.\n");
printf("%s->%s via diff %s yielded %s\n", original, newfile, dotfile, testnewfile);
LOG(file, "Delta xattrs mismatch:", "%s->%s via diff %s yielded %s", original, newfile, dotfile, testnewfile);
assert(0);
goto out;
}
char *const sanitycheck[] = { "cmp", "-s", newfile, testnewfile, NULL };
ret = system_argv(sanitycheck);
if (ret == -1 || ret == 2) {
printf("Sanity check system command failed %i. \n", ret);
printf("%s->%s via diff %s yielded %s\n", original, newfile, dotfile, testnewfile);
assert(0);
goto out;
} else if (ret == 1) {
printf("Delta application resulted in file mismatch %i. \n", ret);
printf("%s->%s via diff %s yielded %s\n", original, newfile, dotfile, testnewfile);
LOG(file, "Delta mismatch:", "%s->%s via diff %s yielded %s", original, newfile, dotfile, testnewfile);
#warning this too will have failures due to races
//unlink(testnewfile);
//unlink(dotfile);
ret = 0;
goto out;
}
unlink(testnewfile);
if (rename(dotfile, outfile) != 0) {
if (errno == ENOENT) {
LOG(NULL, "dotfile:", " %s does not exist", dotfile);
}
LOG(NULL, "Failed to rename", "");
}
out:
free(testnewfile);
free(conf);
free(newfile);
free(original);
free(outfile);
free(dotfile);
}
void prepare_delta_dir(struct manifest *manifest)
{
char *path;
char *conf;
printf("Preparing delta directory \n");
conf = config_output_dir();
string_or_die(&path, "%s/%i", conf, manifest->version);
if (mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) {
if (errno != EEXIST) {
LOG(NULL, "Failed to create directory ", "%s", path);
return;
}
}
free(path);
string_or_die(&path, "%s/%i/delta/", conf, manifest->version);
if (mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) {
if (errno != EEXIST) {
LOG(NULL, "Failed to create directory ", "%s", path);
return;
}
}
free(path);
free(conf);
}