summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@iki.fi>2008-11-14 14:26:59 +0200
committerTimo Teras <timo.teras@iki.fi>2008-11-14 14:26:59 +0200
commit8e23a2ba4eb7f6192c6bce8a6da81004803eca3f (patch)
tree1450b08f0e2818a4bc12206081b6777b3e92b7f8
parent86676ac8c40a96880f323c2b1a09a5714d85705e (diff)
downloadapk-tools-8e23a2ba4eb7f6192c6bce8a6da81004803eca3f.tar.bz2
apk-tools-8e23a2ba4eb7f6192c6bce8a6da81004803eca3f.tar.xz
db: checksum installed files, protect config files
Checksum of installed is computed on the fly when extracting them and it'll be saved to fdb. When installing config files those are diverted with suffix .apk-new if earlier version of same file with local changes exist.
-rw-r--r--TODO3
-rw-r--r--src/apk_archive.h18
-rw-r--r--src/apk_database.h5
-rw-r--r--src/apk_defines.h7
-rw-r--r--src/apk_io.h17
-rw-r--r--src/archive.c32
-rw-r--r--src/database.c67
-rw-r--r--src/gunzip.c1
-rw-r--r--src/io.c45
-rw-r--r--src/md5.c2
-rw-r--r--src/package.c2
11 files changed, 136 insertions, 63 deletions
diff --git a/TODO b/TODO
index f31352e..ee62c66 100644
--- a/TODO
+++ b/TODO
@@ -8,9 +8,6 @@
- cache .apks on USB stick when using network repo for reboot
- Installation of .APK files not in any repository
-- Configfiles list in .PKGINFO
-- Implement lbu stuff
-
- Error handling and rollback
- Dependency manipulation API: deletion, overwrite, check compatibility
diff --git a/src/apk_archive.h b/src/apk_archive.h
index b51aee5..ac2387f 100644
--- a/src/apk_archive.h
+++ b/src/apk_archive.h
@@ -16,29 +16,17 @@
#include "apk_blob.h"
#include "apk_io.h"
-struct apk_archive_entry {
- char *name;
- char *link_target;
- char *uname;
- char *gname;
- off_t size;
- uid_t uid;
- gid_t gid;
- mode_t mode;
- time_t mtime;
- dev_t device;
-};
-
typedef int (*apk_archive_entry_parser)(void *ctx,
- const struct apk_archive_entry *ae,
+ const struct apk_file_info *ae,
struct apk_istream *istream);
+int apk_file_get_info(const char *filename, struct apk_file_info *fi);
struct apk_istream *apk_gunzip_bstream(struct apk_bstream *);
int apk_parse_tar(struct apk_istream *, apk_archive_entry_parser parser, void *ctx);
int apk_parse_tar_gz(struct apk_bstream *, apk_archive_entry_parser parser, void *ctx);
-int apk_archive_entry_extract(const struct apk_archive_entry *ae,
+int apk_archive_entry_extract(const struct apk_file_info *ae,
struct apk_istream *is,
const char *to);
diff --git a/src/apk_database.h b/src/apk_database.h
index d687bce..5cf2928 100644
--- a/src/apk_database.h
+++ b/src/apk_database.h
@@ -25,9 +25,12 @@ struct apk_db_file {
struct apk_db_dir *dir;
struct apk_package *owner;
+ csum_t csum;
char filename[];
};
+#define APK_DBDIRF_PROTECTED 0x0001
+
struct apk_db_dir {
apk_hash_node hash_node;
@@ -38,6 +41,7 @@ struct apk_db_dir {
mode_t mode;
uid_t uid;
gid_t gid;
+ unsigned flags;
char dirname[];
};
@@ -58,6 +62,7 @@ struct apk_database {
unsigned pkg_id, num_repos;
struct apk_dependency_array *world;
+ struct apk_string_array *protected_paths;
struct apk_repository repos[APK_MAX_REPOS];
struct {
diff --git a/src/apk_defines.h b/src/apk_defines.h
index d6557a2..64abe72 100644
--- a/src/apk_defines.h
+++ b/src/apk_defines.h
@@ -12,6 +12,8 @@
#ifndef APK_DEFINES_H
#define APK_DEFINES_H
+#include <malloc.h>
+
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define BIT(x) (1 << (x))
@@ -36,12 +38,15 @@
#if 1
#include "md5.h"
+typedef unsigned char *csum_p;
typedef md5sum_t csum_t;
typedef struct md5_ctx csum_ctx_t;
+extern csum_t bad_checksum;
#define csum_init(ctx) md5_init(ctx)
#define csum_process(ctx, buf, len) md5_process(ctx, buf, len)
#define csum_finish(ctx, buf) md5_finish(ctx, buf)
+#define csum_valid(buf) memcmp(buf, bad_checksum, sizeof(csum_t))
#endif
extern int apk_cwd_fd, apk_quiet;
@@ -76,6 +81,8 @@ void apk_log(const char *prefix, const char *format, ...);
return &(*a)->item[size-1]; \
}
+APK_ARRAY(apk_string_array, char *);
+
#define LIST_END (void *) 0xe01
#define LIST_POISON1 (void *) 0xdeadbeef
#define LIST_POISON2 (void *) 0xabbaabba
diff --git a/src/apk_io.h b/src/apk_io.h
index a0ceac2..0eadec0 100644
--- a/src/apk_io.h
+++ b/src/apk_io.h
@@ -14,15 +14,28 @@
#include "apk_defines.h"
#include "apk_blob.h"
+struct apk_file_info {
+ char *name;
+ char *link_target;
+ char *uname;
+ char *gname;
+ off_t size;
+ uid_t uid;
+ gid_t gid;
+ mode_t mode;
+ time_t mtime;
+ dev_t device;
+ csum_t csum;
+};
+
struct apk_istream {
size_t (*read)(void *stream, void *ptr, size_t size);
- size_t (*splice)(void *stream, int fd, size_t size);
void (*close)(void *stream);
};
struct apk_bstream {
size_t (*read)(void *stream, void **ptr);
- void (*close)(void *stream, csum_t csum);
+ void (*close)(void *stream, csum_p csum);
};
struct apk_istream *apk_istream_from_fd(int fd);
diff --git a/src/archive.c b/src/archive.c
index 33e3428..6562297 100644
--- a/src/archive.c
+++ b/src/archive.c
@@ -53,6 +53,8 @@ struct apk_tar_entry_istream {
struct apk_istream is;
struct apk_istream *tar_is;
size_t bytes_left;
+ csum_ctx_t csum_ctx;
+ csum_p csum;
};
static size_t tar_entry_read(void *stream, void *ptr, size_t size)
@@ -63,33 +65,24 @@ static size_t tar_entry_read(void *stream, void *ptr, size_t size)
if (size > teis->bytes_left)
size = teis->bytes_left;
size = teis->tar_is->read(teis->tar_is, ptr, size);
- if (size >= 0)
- teis->bytes_left -= size;
- return size;
-}
-
-static size_t tar_entry_splice(void *stream, int fd, size_t size)
-{
- struct apk_tar_entry_istream *teis =
- container_of(stream, struct apk_tar_entry_istream, is);
-
- if (size > teis->bytes_left)
- size = teis->bytes_left;
- size = teis->tar_is->splice(teis->tar_is, fd, size);
- if (size >= 0)
+ if (size > 0) {
teis->bytes_left -= size;
+ csum_process(&teis->csum_ctx, ptr, size);
+ if (teis->bytes_left == 0)
+ csum_finish(&teis->csum_ctx, teis->csum);
+ }
return size;
}
int apk_parse_tar(struct apk_istream *is, apk_archive_entry_parser parser,
void *ctx)
{
+ struct apk_file_info entry;
struct apk_tar_entry_istream teis = {
.is.read = tar_entry_read,
- .is.splice = tar_entry_splice,
.tar_is = is,
+ .csum = entry.csum,
};
- struct apk_archive_entry entry;
struct tar_header buf;
unsigned long offset = 0;
int end = 0, r;
@@ -107,7 +100,7 @@ int apk_parse_tar(struct apk_istream *is, apk_archive_entry_parser parser,
continue;
}
- entry = (struct apk_archive_entry){
+ entry = (struct apk_file_info){
.size = GET_OCTAL(buf.size),
.uid = GET_OCTAL(buf.uid),
.gid = GET_OCTAL(buf.gid),
@@ -160,6 +153,7 @@ int apk_parse_tar(struct apk_istream *is, apk_archive_entry_parser parser,
entry.name = strdup(buf.name);
/* callback parser function */
+ csum_init(&teis.csum_ctx);
r = parser(ctx, &entry, &teis.is);
if (r != 0)
return r;
@@ -191,7 +185,7 @@ int apk_parse_tar_gz(struct apk_bstream *bs, apk_archive_entry_parser parser,
return apk_parse_tar(apk_gunzip_bstream(bs), parser, ctx);
}
-int apk_archive_entry_extract(const struct apk_archive_entry *ae,
+int apk_archive_entry_extract(const struct apk_file_info *ae,
struct apk_istream *is,
const char *fn)
{
@@ -216,7 +210,7 @@ int apk_archive_entry_extract(const struct apk_archive_entry *ae,
r = -1;
break;
}
- if (is->splice(is, fd, ae->size) == ae->size)
+ if (apk_istream_splice(is, fd, ae->size) == ae->size)
r = 0;
close(fd);
} else {
diff --git a/src/database.c b/src/database.c
index 15757ff..4ed3ece 100644
--- a/src/database.c
+++ b/src/database.c
@@ -12,6 +12,7 @@
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
+#include <limits.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
@@ -137,6 +138,7 @@ static struct apk_db_dir *apk_db_dir_get(struct apk_database *db,
struct apk_db_dir *dir;
apk_blob_t bparent;
char *cstr;
+ int i;
if (name.len && name.ptr[name.len-1] == '/')
name.len--;
@@ -154,11 +156,22 @@ static struct apk_db_dir *apk_db_dir_get(struct apk_database *db,
if (name.len == 0)
dir->parent = NULL;
- else if (apk_blob_rsplit(name, '/', &bparent, NULL))
+ else if (apk_blob_rsplit(name, '/', &bparent, NULL))
dir->parent = apk_db_dir_get(db, bparent);
else
dir->parent = apk_db_dir_get(db, APK_BLOB_NULL);
+ if (dir->parent != NULL)
+ dir->flags = dir->parent->flags;
+
+ for (i = 0; i < db->protected_paths->num; i++) {
+ if (db->protected_paths->item[i][0] == '-' &&
+ strcmp(&db->protected_paths->item[i][1], dir->dirname) == 0)
+ dir->flags &= ~APK_DBDIRF_PROTECTED;
+ else if (strcmp(db->protected_paths->item[i], dir->dirname) == 0)
+ dir->flags |= APK_DBDIRF_PROTECTED;
+ }
+
return dir;
}
@@ -295,6 +308,16 @@ static int apk_db_read_fdb(struct apk_database *db, int fd)
file_dir_node = &file->dir_files_list.next;
file_pkg_node = &file->pkg_files_list.next;
break;
+ case 'C':
+ if (file == NULL) {
+ apk_error("FDB checksum entry before file entry");
+ return -1;
+ }
+ if (apk_hexdump_parse(APK_BLOB_BUF(file->csum), l)) {
+ apk_error("Not a valid checksum");
+ return -1;
+ }
+ break;
default:
apk_error("FDB entry '%c' unsupported", n);
return -1;
@@ -342,6 +365,12 @@ static int apk_db_write_fdb(struct apk_database *db, int fd)
n += snprintf(&buf[n], sizeof(buf)-n,
"F%s\n",
file->filename);
+ if (csum_valid(file->csum)) {
+ n += snprintf(&buf[n], sizeof(buf)-n, "C");
+ n += apk_hexdump_format(sizeof(buf)-n, &buf[n],
+ APK_BLOB_BUF(file->csum));
+ n += snprintf(&buf[n], sizeof(buf)-n, "\n");
+ }
if (write(fd, buf, n) != n)
return -1;
@@ -418,7 +447,7 @@ int apk_db_create(const char *root)
return 0;
}
-static int apk_db_read_config(struct apk_database *db)
+static int apk_db_read_state(struct apk_database *db)
{
struct apk_istream *is;
struct stat st;
@@ -466,8 +495,18 @@ static int apk_db_read_config(struct apk_database *db)
return 0;
}
+static int add_protected_path(void *ctx, apk_blob_t blob)
+{
+ struct apk_database *db = (struct apk_database *) ctx;
+
+ *apk_string_array_add(&db->protected_paths) = apk_blob_cstr(blob);
+ return 0;
+}
+
int apk_db_open(struct apk_database *db, const char *root)
{
+ apk_blob_t dirs;
+
memset(db, 0, sizeof(*db));
apk_hash_init(&db->available.names, &pkg_name_hash_ops, 1000);
apk_hash_init(&db->available.packages, &pkg_info_hash_ops, 4000);
@@ -485,7 +524,10 @@ int apk_db_open(struct apk_database *db, const char *root)
if (apk_repository != NULL)
apk_db_add_repository(db, apk_repository);
- return apk_db_read_config(db);
+ dirs = APK_BLOB_STR("etc:-etc/init.d");
+ apk_blob_for_each_segment(dirs, ":", add_protected_path, db);
+
+ return apk_db_read_state(db);
}
struct write_ctx {
@@ -668,7 +710,7 @@ int apk_db_recalculate_and_commit(struct apk_database *db)
}
static int apk_db_install_archive_entry(void *_ctx,
- const struct apk_archive_entry *ae,
+ const struct apk_file_info *ae,
struct apk_istream *is)
{
struct install_ctx *ctx = (struct install_ctx *) _ctx;
@@ -677,6 +719,8 @@ static int apk_db_install_archive_entry(void *_ctx,
apk_blob_t name = APK_BLOB_STR(ae->name);
struct apk_db_dir *dir;
struct apk_db_file *file;
+ struct apk_file_info fi;
+ char alt_name[PATH_MAX];
const char *p;
int r = 0, type = APK_SCRIPT_INVALID;
@@ -740,7 +784,20 @@ static int apk_db_install_archive_entry(void *_ctx,
if (strncmp(file->filename, ".keep_", 6) == 0)
return 0;
- r = apk_archive_entry_extract(ae, is, NULL);
+ if ((file->dir->flags & APK_DBDIRF_PROTECTED) &&
+ csum_valid(file->csum) &&
+ apk_file_get_info(ae->name, &fi) == 0 &&
+ memcmp(file->csum, fi.csum, sizeof(csum_t)) != 0) {
+ /* Protected file, which is modified locally.
+ * Extract to separate place */
+ snprintf(alt_name, sizeof(alt_name),
+ "%s/%s.apk-new",
+ dir->dirname, file->filename);
+ r = apk_archive_entry_extract(ae, is, alt_name);
+ } else {
+ r = apk_archive_entry_extract(ae, is, NULL);
+ }
+ memcpy(file->csum, ae->csum, sizeof(csum_t));
} else {
if (name.ptr[name.len-1] == '/')
name.len--;
diff --git a/src/gunzip.c b/src/gunzip.c
index f488fa4..cfee860 100644
--- a/src/gunzip.c
+++ b/src/gunzip.c
@@ -77,7 +77,6 @@ struct apk_istream *apk_gunzip_bstream(struct apk_bstream *bs)
*gis = (struct apk_gzip_istream) {
.is.read = gz_read,
- .is.splice = apk_istream_splice,
.is.close = gz_close,
.bs = bs,
.z_err = 0,
diff --git a/src/io.c b/src/io.c
index 418c7f8..2bb8afc 100644
--- a/src/io.c
+++ b/src/io.c
@@ -47,22 +47,6 @@ static size_t fd_read(void *stream, void *ptr, size_t size)
return i;
}
-static size_t fd_splice(void *stream, int fd, size_t size)
-{
- struct apk_fd_istream *fis =
- container_of(stream, struct apk_fd_istream, is);
- size_t i = 0, r;
-
- while (i != size) {
- r = splice(fis->fd, NULL, fd, NULL, size - i, SPLICE_F_MOVE);
- if (r == -1)
- return i;
- i += r;
- }
-
- return i;
-}
-
static void fd_close(void *stream)
{
struct apk_fd_istream *fis =
@@ -82,7 +66,6 @@ struct apk_istream *apk_istream_from_fd(int fd)
*fis = (struct apk_fd_istream) {
.is.read = fd_read,
- .is.splice = fd_splice,
.is.close = fd_close,
.fd = fd,
};
@@ -322,3 +305,31 @@ apk_blob_t apk_blob_from_istream(struct apk_istream *is, size_t size)
return APK_BLOB_PTR_LEN(ptr, rsize);
}
+int apk_file_get_info(const char *filename, struct apk_file_info *fi)
+{
+ struct stat st;
+ struct apk_bstream *bs;
+ int fd;
+
+ if (stat(filename, &st) != 0)
+ return -1;
+
+ *fi = (struct apk_file_info) {
+ .size = st.st_size,
+ .uid = st.st_uid,
+ .gid = st.st_gid,
+ .mode = st.st_mode,
+ .mtime = st.st_mtime,
+ .device = st.st_dev,
+ };
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return 0;
+
+ bs = apk_bstream_from_fd(fd);
+ if (bs != NULL)
+ bs->close(bs, fi->csum);
+
+ return 0;
+}
diff --git a/src/md5.c b/src/md5.c
index e165724..82e670b 100644
--- a/src/md5.c
+++ b/src/md5.c
@@ -58,6 +58,8 @@
#include "md5.h"
+md5sum_t bad_checksum = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
/* Handle endian-ness */
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define SWAP(n) (n)
diff --git a/src/package.c b/src/package.c
index 165656d..3430d19 100644
--- a/src/package.c
+++ b/src/package.c
@@ -255,7 +255,7 @@ static int read_info_line(void *ctx, apk_blob_t line)
return 0;
}
-static int read_info_entry(void *ctx, const struct apk_archive_entry *ae,
+static int read_info_entry(void *ctx, const struct apk_file_info *ae,
struct apk_istream *is)
{
static struct {