summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 {