diff options
author | Timo Teras <timo.teras@iki.fi> | 2008-11-14 14:26:59 +0200 |
---|---|---|
committer | Timo Teras <timo.teras@iki.fi> | 2008-11-14 14:26:59 +0200 |
commit | 8e23a2ba4eb7f6192c6bce8a6da81004803eca3f (patch) | |
tree | 1450b08f0e2818a4bc12206081b6777b3e92b7f8 /src | |
parent | 86676ac8c40a96880f323c2b1a09a5714d85705e (diff) | |
download | aports-8e23a2ba4eb7f6192c6bce8a6da81004803eca3f.tar.bz2 aports-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.
Diffstat (limited to 'src')
-rw-r--r-- | src/apk_archive.h | 18 | ||||
-rw-r--r-- | src/apk_database.h | 5 | ||||
-rw-r--r-- | src/apk_defines.h | 7 | ||||
-rw-r--r-- | src/apk_io.h | 17 | ||||
-rw-r--r-- | src/archive.c | 32 | ||||
-rw-r--r-- | src/database.c | 67 | ||||
-rw-r--r-- | src/gunzip.c | 1 | ||||
-rw-r--r-- | src/io.c | 45 | ||||
-rw-r--r-- | src/md5.c | 2 | ||||
-rw-r--r-- | src/package.c | 2 |
10 files changed, 136 insertions, 60 deletions
diff --git a/src/apk_archive.h b/src/apk_archive.h index b51aee50fd..ac2387fd4a 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 d687bcec15..5cf2928ce7 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 d6557a24a5..64abe728b4 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 a0ceac2e47..0eadec015d 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 33e3428155..65622975b2 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 15757ff1e9..4ed3ece736 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 f488fa4497..cfee86064f 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, @@ -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; +} @@ -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 165656dbb0..3430d19385 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 { |