Resource *rr,
DIR* d,
const char* relpath,
- mode_t m) {
+ const char* relpath_for_matching,
+ mode_t m,
+ bool ancestor_is_partial,
+ bool ancestor_is_pending) {
int r;
for (;;) {
_cleanup_(instance_metadata_destroy) InstanceMetadata extracted_fields = INSTANCE_METADATA_NULL;
_cleanup_free_ char *joined = NULL, *rel_joined = NULL;
+ _cleanup_free_ char *rel_joined_for_matching = NULL;
Instance *instance;
struct dirent *de;
+ const char *de_d_name_stripped;
struct stat st;
+ bool is_partial = ancestor_is_partial, is_pending = ancestor_is_pending;
+ const char *stripped;
errno = 0;
de = readdir_no_dot(d);
if (!(S_ISDIR(st.st_mode) && S_ISREG(m)) && ((st.st_mode & S_IFMT) != m))
continue;
+ if ((stripped = startswith(de->d_name, ".sysupdate.partial."))) {
+ de_d_name_stripped = stripped;
+ is_partial = true;
+ } else if ((stripped = startswith(de->d_name, ".sysupdate.pending."))) {
+ de_d_name_stripped = stripped;
+ is_pending = true;
+ } else
+ de_d_name_stripped = de->d_name;
+
rel_joined = path_join(relpath, de->d_name);
if (!rel_joined)
return log_oom();
- r = pattern_match_many(rr->patterns, rel_joined, &extracted_fields);
+ /* Match against the filename with any `.sysupdate.partial.` (etc.) prefix stripped, so the
+ * user’s patterns still apply. But don’t use the stripped version in any paths or recursion. */
+ rel_joined_for_matching = path_join(relpath_for_matching, de_d_name_stripped);
+ if (!rel_joined_for_matching)
+ return log_oom();
+
+ r = pattern_match_many(rr->patterns, rel_joined_for_matching, &extracted_fields);
if (r == PATTERN_MATCH_RETRY) {
_cleanup_closedir_ DIR *subdir = NULL;
if (!subdir)
continue;
- r = resource_load_from_directory_recursive(rr, subdir, rel_joined, m);
+ r = resource_load_from_directory_recursive(rr, subdir, rel_joined, rel_joined_for_matching, m, is_partial, is_pending);
if (r < 0)
return r;
if (r == 0)
if (instance->metadata.mode == MODE_INVALID)
instance->metadata.mode = st.st_mode & 0775; /* mask out world-writability and suid and stuff, for safety */
+
+ instance->is_partial = is_partial;
+ instance->is_pending = is_pending;
}
return 0;
return log_error_errno(errno, "Failed to open directory '%s': %m", rr->path);
}
- return resource_load_from_directory_recursive(rr, d, NULL, m);
+ return resource_load_from_directory_recursive(rr, d, NULL, NULL, m, false, false);
}
static int resource_load_from_blockdev(Resource *rr) {
_cleanup_(instance_metadata_destroy) InstanceMetadata extracted_fields = INSTANCE_METADATA_NULL;
_cleanup_(partition_info_destroy) PartitionInfo pinfo = PARTITION_INFO_NULL;
Instance *instance;
+ const char *pinfo_label_stripped;
+ bool is_partial = false, is_pending = false;
+ const char *stripped;
r = read_partition_info(c, t, i, &pinfo);
if (r < 0)
continue;
}
- r = pattern_match_many(rr->patterns, pinfo.label, &extracted_fields);
+ /* Match the label with any partial/pending prefix removed so the user’s existing patterns
+ * match regardless of the instance’s state. */
+ if ((stripped = startswith(pinfo.label, "PRT#"))) {
+ pinfo_label_stripped = stripped;
+ is_partial = true;
+ } else if ((stripped = startswith(pinfo.label, "PND#"))) {
+ pinfo_label_stripped = stripped;
+ is_pending = true;
+ } else
+ pinfo_label_stripped = pinfo.label;
+
+ r = pattern_match_many(rr->patterns, pinfo_label_stripped, &extracted_fields);
if (r < 0)
return log_error_errno(r, "Failed to match pattern: %m");
if (IN_SET(r, PATTERN_MATCH_NO, PATTERN_MATCH_RETRY))
if (instance->metadata.read_only < 0)
instance->metadata.read_only = instance->partition_info.read_only;
+
+ instance->is_partial = is_partial;
+ instance->is_pending = is_pending;
}
return 0;
memcpy(instance->metadata.sha256sum, h.iov_base, h.iov_len);
instance->metadata.sha256sum_set = true;
}
+
+ /* Web resources can only be a source, not a target, so
+ * can never be partial or pending. */
+ instance->is_partial = false;
+ instance->is_pending = false;
}
}