mirror of
https://github.com/clearlinux/swupd-server.git
synced 2026-08-19 04:57:43 +00:00
9c1a4a3542
For three different Clear Linux OS builds in the last few months, deltas were created between files with type change L->F (symlink to file). This was allowed to occur because there is no check if file->peer->is_link in __create_delta(). Instead, remove the file->is_link check and simply ensure that the from/to file types are both F (i.e. "regular file"). Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
175 lines
5.1 KiB
C
175 lines
5.1 KiB
C
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Authors:
|
|
* Arjan van de Ven <arjan@linux.intel.com>
|
|
*
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
#include <assert.h>
|
|
#include <bsdiff.h>
|
|
#include <errno.h>
|
|
#include <glib.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#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);
|
|
}
|