diff options
Diffstat (limited to 'src/database.c')
-rw-r--r-- | src/database.c | 171 |
1 files changed, 125 insertions, 46 deletions
diff --git a/src/database.c b/src/database.c index 9da4815..da3dcb9 100644 --- a/src/database.c +++ b/src/database.c @@ -245,7 +245,7 @@ static void apk_db_dir_unref(struct apk_database *db, struct apk_db_dir *dir, dir->refs--; if (dir->refs > 0) { if (allow_rmdir) { - dir->flags |= APK_DBDIRF_RECALC_MODE; + dir->recalc_mode = 1; dir->mode = 0; dir->uid = (uid_t) -1; dir->gid = (gid_t) -1; @@ -258,13 +258,13 @@ static void apk_db_dir_unref(struct apk_database *db, struct apk_db_dir *dir, if (allow_rmdir) { /* The final instance of this directory was removed, * so this directory gets deleted in reality too. */ - dir->flags &= ~APK_DBDIRF_RECALC_MODE; + dir->recalc_mode = 0; dir->mode = 0; dir->uid = (uid_t) -1; dir->gid = (gid_t) -1; unlinkat(db->root_fd, dir->name, AT_REMOVEDIR); - } else if (dir->flags & APK_DBDIRF_RECALC_MODE) { + } else if (dir->recalc_mode) { /* Directory permissions need a reset. */ apk_db_dir_mkdir(db, dir); } @@ -285,12 +285,13 @@ struct apk_db_dir *apk_db_dir_query(struct apk_database *db, return (struct apk_db_dir *) apk_hash_get(&db->installed.dirs, name); } -static struct apk_db_dir *apk_db_dir_get(struct apk_database *db, - apk_blob_t name) +struct apk_db_dir *apk_db_dir_get(struct apk_database *db, apk_blob_t name) { struct apk_db_dir *dir; + struct apk_protected_path_array *ppaths; apk_blob_t bparent; unsigned long hash = apk_hash_from_key(&db->installed.dirs, name); + char *relative_name; int i; if (name.len && name.ptr[name.len-1] == '/') @@ -311,38 +312,54 @@ static struct apk_db_dir *apk_db_dir_get(struct apk_database *db, dir->name[name.len] = 0; dir->namelen = name.len; dir->hash = hash; + apk_protected_path_array_init(&dir->protected_paths); apk_hash_insert_hashed(&db->installed.dirs, dir, hash); - if (name.len == 0) + if (name.len == 0) { dir->parent = NULL; - else if (apk_blob_rsplit(name, '/', &bparent, NULL)) + dir->has_protected_children = 1; + ppaths = NULL; + } else if (apk_blob_rsplit(name, '/', &bparent, NULL)) { dir->parent = apk_db_dir_get(db, bparent); - else + dir->protected = dir->parent->protected; + dir->has_protected_children = dir->protected; + dir->symlinks_only = dir->parent->symlinks_only; + ppaths = dir->parent->protected_paths; + } else { dir->parent = apk_db_dir_get(db, APK_BLOB_NULL); + ppaths = db->protected_paths; + } - if (dir->parent != NULL) - dir->flags = dir->parent->flags; + if (ppaths == NULL) + return dir; - for (i = 0; i < db->protected_paths->num; i++) { - int flags = dir->flags, j; + relative_name = strrchr(dir->rooted_name, '/') + 1; + for (i = 0; i < ppaths->num; i++) { + struct apk_protected_path *ppath = &ppaths->item[i]; + char *slash; - flags |= APK_DBDIRF_PROTECTED; - for (j = 0; ; j++) { - switch (db->protected_paths->item[i][j]) { - case '-': - flags &= ~(APK_DBDIRF_PROTECTED | - APK_DBDIRF_SYMLINKS_ONLY); - continue; - case '*': - flags |= APK_DBDIRF_SYMLINKS_ONLY | - APK_DBDIRF_PROTECTED; + slash = strchr(ppath->relative_pattern, '/'); + if (slash != NULL) { + *slash = 0; + if (fnmatch(ppath->relative_pattern, relative_name, FNM_PATHNAME) != 0) { + *slash = '/'; continue; } - break; - } + *slash = '/'; + + *apk_protected_path_array_add(&dir->protected_paths) = (struct apk_protected_path) { + .relative_pattern = slash + 1, + .protected = ppath->protected, + .symlinks_only = ppath->symlinks_only, + }; + dir->has_protected_children |= ppath->protected; + } else { + if (fnmatch(ppath->relative_pattern, relative_name, FNM_PATHNAME) != 0) + continue; - if (strcmp(&db->protected_paths->item[i][j], dir->name) == 0) - dir->flags = flags; + dir->protected = ppath->protected; + dir->symlinks_only = ppath->symlinks_only; + } } return dir; @@ -393,8 +410,8 @@ static void apk_db_diri_free(struct apk_database *db, struct apk_db_dir_instance *diri, int allow_rmdir) { - if ((allow_rmdir == APK_DISALLOW_RMDIR) && - (diri->dir->flags & APK_DBDIRF_RECALC_MODE)) + if (allow_rmdir == APK_DISALLOW_RMDIR && + diri->dir->recalc_mode) apk_db_dir_apply_diri_permissions(diri); apk_db_dir_unref(db, diri->dir, allow_rmdir); @@ -407,6 +424,9 @@ struct apk_db_file *apk_db_file_query(struct apk_database *db, { struct apk_db_file_hash_key key; + if (dir.len && dir.ptr[dir.len-1] == '/') + dir.len--; + key = (struct apk_db_file_hash_key) { .dirname = dir, .filename = name, @@ -1120,8 +1140,67 @@ int apk_db_index_write(struct apk_database *db, struct apk_ostream *os) static int add_protected_path(void *ctx, apk_blob_t blob) { struct apk_database *db = (struct apk_database *) ctx; + int protected = 0, symlinks_only = 0; + + /* skip empty lines and comments */ + if (blob.len == 0) + return 0; + + switch (blob.ptr[0]) { + case '#': + return 0; + case '-': + blob.ptr++; + blob.len--; + break; + case '@': + protected = 1; + symlinks_only = 1; + blob.ptr++; + blob.len--; + break; + case '+': + protected = 1; + blob.ptr++; + blob.len--; + break; + default: + protected = 1; + break; + } + + *apk_protected_path_array_add(&db->protected_paths) = (struct apk_protected_path) { + .relative_pattern = apk_blob_cstr(blob), + .protected = protected, + .symlinks_only = symlinks_only, + }; + + return 0; +} + +static int file_ends_with_dot_list(const char *file) +{ + const char *ext = strrchr(file, '.'); + if (ext == NULL || strcmp(ext, ".list") != 0) + return FALSE; + return TRUE; +} + +static int add_protected_paths_from_file(void *ctx, int dirfd, const char *file) +{ + struct apk_database *db = (struct apk_database *) ctx; + apk_blob_t blob; + + if (!file_ends_with_dot_list(file)) + return 0; + + blob = apk_blob_from_file(dirfd, file); + if (APK_BLOB_IS_NULL(blob)) + return 0; + + apk_blob_for_each_segment(blob, "\n", add_protected_path, db); + free(blob.ptr); - *apk_string_array_add(&db->protected_paths) = apk_blob_cstr(blob); return 0; } @@ -1238,10 +1317,8 @@ static int add_repos_from_file(void *ctx, int dirfd, const char *file) apk_blob_t blob; if (dirfd != db->root_fd) { - /* if loading from repositories.d, - * the name must end in .list */ - const char *ext = strrchr(file, '.'); - if (ext == NULL || strcmp(ext, ".list") != 0) + /* loading from repositories.d; check extension */ + if (!file_ends_with_dot_list(file)) return 0; } @@ -1282,7 +1359,7 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts) list_init(&db->installed.packages); list_init(&db->installed.triggers); apk_dependency_array_init(&db->world); - apk_string_array_init(&db->protected_paths); + apk_protected_path_array_init(&db->protected_paths); db->permanent = 1; /* Get first repository tag (the NULL tag) */ @@ -1348,8 +1425,11 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts) } } - blob = APK_BLOB_STR("etc:*etc/init.d"); - apk_blob_for_each_segment(blob, ":", add_protected_path, db); + blob = APK_BLOB_STR("+etc\n" "@etc/init.d\n"); + apk_blob_for_each_segment(blob, "\n", add_protected_path, db); + + apk_dir_foreach_file(openat(db->root_fd, "etc/apk/protected_paths.d", O_RDONLY | O_CLOEXEC), + add_protected_paths_from_file, db); /* figure out where to have the cache */ fd = openat(db->root_fd, apk_linked_cache_dir, O_RDONLY | O_CLOEXEC); @@ -1546,9 +1626,10 @@ void apk_db_close(struct apk_database *db) free(db->repos[i].description.ptr); } for (i = 0; i < db->protected_paths->num; i++) - free(db->protected_paths->item[i]); + free(db->protected_paths->item[i].relative_pattern); + apk_protected_path_array_free(&db->protected_paths); + apk_dependency_array_free(&db->world); - apk_string_array_free(&db->protected_paths); apk_hash_free(&db->available.packages); apk_hash_free(&db->available.names); @@ -1602,8 +1683,7 @@ static int fire_triggers(apk_hash_item item, void *ctx) int i; list_for_each_entry(ipkg, &db->installed.triggers, trigger_pkgs_list) { - if ((!ipkg->run_all_triggers) && - ((dbd->flags & APK_DBDIRF_MODIFIED) == 0)) + if (!ipkg->run_all_triggers && !dbd->modified) continue; for (i = 0; i < ipkg->triggers->num; i++) { @@ -2243,7 +2323,7 @@ static void apk_db_purge_pkg(struct apk_database *db, hlist_for_each_entry_safe(diri, dc, dn, &ipkg->owned_dirs, pkg_dirs_list) { if (exten == NULL) - diri->dir->flags |= APK_DBDIRF_MODIFIED; + diri->dir->modified = 1; hlist_for_each_entry_safe(file, fc, fn, &diri->owned_files, diri_files_list) { snprintf(name, sizeof(name), "%s/%s%s", @@ -2254,7 +2334,7 @@ static void apk_db_purge_pkg(struct apk_database *db, .filename = APK_BLOB_PTR_LEN(file->name, file->namelen), }; hash = apk_blob_hash_seed(key.filename, diri->dir->hash); - if (!(diri->dir->flags & APK_DBDIRF_PROTECTED) || + if ((!diri->dir->protected) || (apk_flags & APK_PURGE) || (file->csum.type != APK_CHECKSUM_NONE && apk_file_get_info(db->root_fd, name, APK_FI_NOFOLLOW | file->csum.type, &fi) == 0 && @@ -2289,7 +2369,7 @@ static void apk_db_migrate_files(struct apk_database *db, hlist_for_each_entry_safe(diri, dc, dn, &ipkg->owned_dirs, pkg_dirs_list) { dir = diri->dir; - dir->flags |= APK_DBDIRF_MODIFIED; + dir->modified = 1; hlist_for_each_entry_safe(file, fc, fn, &diri->owned_files, diri_files_list) { snprintf(name, sizeof(name), "%s/%s", @@ -2311,8 +2391,7 @@ static void apk_db_migrate_files(struct apk_database *db, /* We want to compare checksums only if one exists * in db, and the file is in a protected path */ cstype = APK_CHECKSUM_NONE; - if (ofile != NULL && - (diri->dir->flags & APK_DBDIRF_PROTECTED)) + if (ofile != NULL && diri->dir->protected) cstype = ofile->csum.type; cstype |= APK_FI_NOFOLLOW; @@ -2321,7 +2400,7 @@ static void apk_db_migrate_files(struct apk_database *db, /* File was from overlay, delete the * packages version */ unlinkat(db->root_fd, tmpname, 0); - } else if ((diri->dir->flags & APK_DBDIRF_PROTECTED) && + } else if ((diri->dir->protected) && (r == 0) && (ofile == NULL || ofile->csum.type == APK_CHECKSUM_NONE || |