sysupdate: Allow patterns to match path with directories

`MatchPattern` for regular-file and directory as target can now match
subdirectories This is useful to install files for examples in `.extra.d`
directories:

```
[Target]
Type=regular-file
Path=/EFI/Linux
PathRelativeTo=boot
MatchPattern=gnomeos_@v.efi.extra.d/apparmor.addon.efi
```

The if the directories in the path do not exist, they will be created.  Whereas
the part in `Path` is not created.
This commit is contained in:
Valentin David
2023-09-28 11:41:29 +02:00
parent 18c3ffbfcc
commit 8b051623cd
5 changed files with 141 additions and 35 deletions
+50 -8
View File
@@ -23,6 +23,7 @@ typedef enum PatternElementType {
PATTERN_READ_ONLY,
PATTERN_GROWFS,
PATTERN_SHA256SUM,
PATTERN_SLASH,
_PATTERN_ELEMENT_TYPE_MAX,
_PATTERN_ELEMENT_TYPE_INVALID = -EINVAL,
} PatternElementType;
@@ -82,7 +83,7 @@ static bool valid_char(char x) {
if ((unsigned) x < ' ' || x >= 127)
return false;
return !IN_SET(x, '$', '*', '?', '[', ']', '!', '\\', '/', '|');
return !IN_SET(x, '$', '*', '?', '[', ']', '!', '\\', '|');
}
static int pattern_split(
@@ -90,7 +91,7 @@ static int pattern_split(
PatternElement **ret) {
_cleanup_(pattern_element_free_allp) PatternElement *first = NULL;
bool at = false, last_literal = true;
bool at = false, last_literal = true, last_slash = false;
PatternElement *last = NULL;
uint64_t mask_found = 0;
size_t l, k = 0;
@@ -123,7 +124,7 @@ static int pattern_split(
/* We insist that two pattern field markers are separated by some literal string that
* we can use to separate the fields when parsing. */
if (!last_literal)
if (!last_literal && !last_slash)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Found two pattern field markers without separating literal.");
if (ret) {
@@ -139,10 +140,28 @@ static int pattern_split(
}
mask_found |= bit;
last_literal = at = false;
last_slash = last_literal = at = false;
continue;
}
if (*e == '/') {
if (ret) {
PatternElement *z;
z = malloc(offsetof(PatternElement, literal));
if (!z)
return -ENOMEM;
z->type = PATTERN_SLASH;
LIST_INSERT_AFTER(elements, first, last, z);
last = z;
}
last_literal = false;
last_slash = true;
continue ;
}
if (!valid_char(*e))
return log_debug_errno(
SYNTHETIC_ERRNO(EBADRQC),
@@ -150,6 +169,7 @@ static int pattern_split(
(unsigned) *e);
last_literal = true;
last_slash = false;
if (!ret)
continue;
@@ -203,6 +223,16 @@ int pattern_match(const char *pattern, const char *s, InstanceMetadata *ret) {
_cleanup_free_ char *t = NULL;
const char *n;
if (e->type == PATTERN_SLASH) {
if (*p == '/') {
++p;
continue;
} else if (*p == '\0')
goto retry;
else
goto nope;
}
if (e->type == PATTERN_LITERAL) {
const char *k;
@@ -399,13 +429,19 @@ int pattern_match(const char *pattern, const char *s, InstanceMetadata *ret) {
found = (InstanceMetadata) INSTANCE_METADATA_NULL;
}
return true;
return PATTERN_MATCH_YES;
nope:
if (ret)
*ret = (InstanceMetadata) INSTANCE_METADATA_NULL;
return false;
return PATTERN_MATCH_NO;
retry:
if (ret)
*ret = (InstanceMetadata) INSTANCE_METADATA_NULL;
return PATTERN_MATCH_RETRY;
}
int pattern_match_many(char **patterns, const char *s, InstanceMetadata *ret) {
@@ -422,14 +458,14 @@ int pattern_match_many(char **patterns, const char *s, InstanceMetadata *ret) {
found = (InstanceMetadata) INSTANCE_METADATA_NULL;
}
return true;
return r;
}
}
if (ret)
*ret = (InstanceMetadata) INSTANCE_METADATA_NULL;
return false;
return PATTERN_MATCH_NO;
}
int pattern_valid(const char *pattern) {
@@ -465,6 +501,12 @@ int pattern_format(
switch (e->type) {
case PATTERN_SLASH:
if (!strextend(&j, "/"))
return -ENOMEM;
break;
case PATTERN_LITERAL:
if (!strextend(&j, e->literal))
return -ENOMEM;