mirror of
https://github.com/systemd/systemd.git
synced 2026-07-12 18:44:14 +00:00
path-util: unify path_extract_filename/directory into path_split_prefix_filename() (#40608)
This commit is contained in:
@@ -69,15 +69,14 @@ int make_lock_file_for(const char *p, int operation, LockFile *ret) {
|
||||
assert(p);
|
||||
assert(ret);
|
||||
|
||||
r = path_extract_filename(p, &fn);
|
||||
r = path_split_prefix_filename(p, &dn, &fn);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = path_extract_directory(p, &dn);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
t = strjoin(dn, "/.#", fn, ".lck");
|
||||
if (dn)
|
||||
t = strjoin(dn, "/.#", fn, ".lck");
|
||||
else
|
||||
t = strjoin(".#", fn, ".lck");
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
|
||||
@@ -1027,8 +1027,7 @@ int path_find_last_component(const char *path, bool accept_dot_dot, const char *
|
||||
q = path + strlen(path) - 1;
|
||||
|
||||
q = skip_slash_or_dot_backward(path, q);
|
||||
if (!q || /* the root directory */
|
||||
(q == path && *q == '.')) { /* path is "." or "./" */
|
||||
if (!q) { /* the root directory, "." or "./" */
|
||||
if (next)
|
||||
*next = path;
|
||||
if (ret)
|
||||
@@ -1102,18 +1101,17 @@ const char* last_path_component(const char *path) {
|
||||
return path + k;
|
||||
}
|
||||
|
||||
int path_extract_filename(const char *path, char **ret) {
|
||||
_cleanup_free_ char *a = NULL;
|
||||
int path_split_prefix_filename(const char *path, char **ret_dir, char **ret_filename) {
|
||||
_cleanup_free_ char *d = NULL;
|
||||
const char *c, *next = NULL;
|
||||
int r;
|
||||
|
||||
/* Extracts the filename part (i.e. right-most component) from a path, i.e. string that passes
|
||||
* filename_is_valid(). A wrapper around last_path_component(), but eats up trailing
|
||||
* slashes. Returns:
|
||||
/* Split the path into dir prefix/filename pair. Returns:
|
||||
*
|
||||
* -EINVAL → if the path is not valid
|
||||
* -EADDRNOTAVAIL → if only a directory was specified, but no filename, i.e. the root dir
|
||||
* itself or "." is specified
|
||||
* -EADDRNOTAVAIL → if the path refers to the uppermost directory in hierarchy (i.e. has neither
|
||||
* dir prefix nor filename - the root dir itself or ".")
|
||||
* -EDESTADDRREQ → if only a filename was passed, and caller only specifies ret_dir
|
||||
* -ENOMEM → no memory
|
||||
*
|
||||
* Returns >= 0 on success. If the input path has a trailing slash, returns O_DIRECTORY, to
|
||||
@@ -1122,63 +1120,52 @@ int path_extract_filename(const char *path, char **ret) {
|
||||
* This function guarantees to return a fully valid filename, i.e. one that passes
|
||||
* filename_is_valid() – this means "." and ".." are not accepted. */
|
||||
|
||||
if (!path_is_valid(path))
|
||||
if (isempty(path))
|
||||
return -EINVAL;
|
||||
|
||||
r = path_find_last_component(path, false, &next, &c);
|
||||
r = path_find_last_component(path, /* accept_dot_dot = */ false, &next, &c);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) /* root directory */
|
||||
if (r == 0) /* root directory or "." */
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
a = strndup(c, r);
|
||||
if (!a)
|
||||
return -ENOMEM;
|
||||
if (ret_dir) {
|
||||
if (next == path) {
|
||||
if (*path != '/') { /* filename only */
|
||||
if (!ret_filename)
|
||||
return -EDESTADDRREQ;
|
||||
} else {
|
||||
d = strdup("/");
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
}
|
||||
} else {
|
||||
d = strndup(path, next - path);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = TAKE_PTR(a);
|
||||
return strlen(c) > (size_t) r ? O_DIRECTORY : 0;
|
||||
}
|
||||
path_simplify(d);
|
||||
|
||||
int path_extract_directory(const char *path, char **ret) {
|
||||
const char *c, *next = NULL;
|
||||
int r;
|
||||
if (!path_is_valid(d))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* The inverse of path_extract_filename(), i.e. returns the directory path prefix. Returns:
|
||||
*
|
||||
* -EINVAL → if the path is not valid
|
||||
* -EDESTADDRREQ → if no directory was specified in the passed in path, i.e. only a filename was passed
|
||||
* -EADDRNOTAVAIL → if the passed in parameter had no filename but did have a directory, i.e.
|
||||
* the root dir itself or "." was specified
|
||||
* -ENOMEM → no memory (surprise!)
|
||||
*
|
||||
* This function guarantees to return a fully valid path, i.e. one that passes path_is_valid().
|
||||
*/
|
||||
|
||||
r = path_find_last_component(path, false, &next, &c);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) /* empty or root */
|
||||
return isempty(path) ? -EINVAL : -EADDRNOTAVAIL;
|
||||
if (next == path) {
|
||||
if (*path != '/') /* filename only */
|
||||
return -EDESTADDRREQ;
|
||||
|
||||
return strdup_to(ret, "/");
|
||||
}
|
||||
|
||||
_cleanup_free_ char *a = strndup(path, next - path);
|
||||
if (!a)
|
||||
return -ENOMEM;
|
||||
|
||||
path_simplify(a);
|
||||
|
||||
if (!path_is_valid(a))
|
||||
} else if (!path_is_valid(path))
|
||||
/* We didn't validate the dir prefix, hence check if the whole path is valid now */
|
||||
return -EINVAL;
|
||||
|
||||
if (ret)
|
||||
*ret = TAKE_PTR(a);
|
||||
if (ret_filename) {
|
||||
char *fn = strndup(c, r);
|
||||
if (!fn)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
*ret_filename = fn;
|
||||
}
|
||||
|
||||
if (ret_dir)
|
||||
*ret_dir = TAKE_PTR(d);
|
||||
|
||||
return strlen(c) > (size_t) r ? O_DIRECTORY : 0;
|
||||
}
|
||||
|
||||
bool filename_part_is_valid(const char *p) {
|
||||
|
||||
@@ -135,8 +135,15 @@ int fsck_exists_for_fstype(const char *fstype);
|
||||
int path_find_first_component(const char **p, bool accept_dot_dot, const char **ret);
|
||||
int path_find_last_component(const char *path, bool accept_dot_dot, const char **next, const char **ret);
|
||||
const char* last_path_component(const char *path);
|
||||
int path_extract_filename(const char *path, char **ret);
|
||||
int path_extract_directory(const char *path, char **ret);
|
||||
|
||||
int path_split_prefix_filename(const char *path, char **ret_dir, char **ret_filename);
|
||||
static inline int path_extract_filename(const char *path, char **ret) {
|
||||
return path_split_prefix_filename(path, NULL, ret);
|
||||
}
|
||||
static inline int path_extract_directory(const char *path, char **ret) {
|
||||
int r = path_split_prefix_filename(path, ret, NULL);
|
||||
return r < 0 ? r : 0; /* suppress O_DIRECTORY */
|
||||
}
|
||||
|
||||
bool filename_part_is_valid(const char *p) _pure_;
|
||||
bool filename_is_valid(const char *p) _pure_;
|
||||
|
||||
@@ -161,17 +161,12 @@ static int tempfn_build(const char *p, const char *pre, const char *post, bool c
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
r = path_extract_directory(p, &d);
|
||||
if (r < 0 && r != -EDESTADDRREQ) /* EDESTADDRREQ → No directory specified, just a filename */
|
||||
return r;
|
||||
|
||||
r = path_extract_filename(p, &fn);
|
||||
r = path_split_prefix_filename(p, &d, &fn);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (strlen(fn) > NAME_MAX - len_add)
|
||||
/* We cannot simply prepend and append strings to the filename. Let's truncate the filename. */
|
||||
fn[NAME_MAX - len_add] = '\0';
|
||||
/* Truncate the filename if it would become too long after mangling. */
|
||||
strshorten(fn, NAME_MAX - len_add);
|
||||
}
|
||||
|
||||
nf = strjoin(".#", strempty(pre), strempty(fn), strempty(post));
|
||||
|
||||
@@ -922,6 +922,7 @@ int blockdev_get_root(int level, dev_t *ret) {
|
||||
}
|
||||
|
||||
int partition_node_of(const char *node, unsigned nr, char **ret) {
|
||||
_cleanup_free_ char *fn = NULL, *dn = NULL;
|
||||
int r;
|
||||
|
||||
assert(node);
|
||||
@@ -931,18 +932,12 @@ int partition_node_of(const char *node, unsigned nr, char **ret) {
|
||||
/* Given a device node path to a block device returns the device node path to the partition block
|
||||
* device of the specified partition */
|
||||
|
||||
_cleanup_free_ char *fn = NULL;
|
||||
r = path_extract_filename(node, &fn);
|
||||
r = path_split_prefix_filename(node, &dn, &fn);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == O_DIRECTORY)
|
||||
return -EISDIR;
|
||||
|
||||
_cleanup_free_ char *dn = NULL;
|
||||
r = path_extract_directory(node, &dn);
|
||||
if (r < 0 && r != -EDESTADDRREQ) /* allow if only filename is specified */
|
||||
return r;
|
||||
|
||||
size_t l = strlen(fn);
|
||||
assert(l > 0); /* underflow check for the subtraction below */
|
||||
|
||||
|
||||
@@ -480,14 +480,13 @@ int get_credential_host_secret(CredentialSecretFlags flags, struct iovec *ret) {
|
||||
if (!path_is_absolute(e))
|
||||
return -EINVAL;
|
||||
|
||||
r = path_extract_directory(e, &_dirname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = path_extract_filename(e, &_filename);
|
||||
r = path_split_prefix_filename(e, &_dirname, &_filename);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == O_DIRECTORY)
|
||||
return -EINVAL;
|
||||
|
||||
/* We validate that the path is absolute above, hence dirname must be extractable. */
|
||||
dirname = _dirname;
|
||||
filename = _filename;
|
||||
} else {
|
||||
@@ -498,7 +497,8 @@ int get_credential_host_secret(CredentialSecretFlags flags, struct iovec *ret) {
|
||||
assert(dirname);
|
||||
assert(filename);
|
||||
|
||||
mkdir_parents(dirname, 0755);
|
||||
(void) mkdir_parents(dirname, 0755);
|
||||
|
||||
dfd = open_mkdir(dirname, O_CLOEXEC, 0755);
|
||||
if (dfd < 0)
|
||||
return log_debug_errno(dfd, "Failed to create or open directory '%s': %m", dirname);
|
||||
|
||||
@@ -109,13 +109,9 @@ int generator_add_symlink_full(
|
||||
*
|
||||
* If <instance> is specified, then <src> must be a template unit name, and we'll instantiate it. */
|
||||
|
||||
r = path_extract_directory(src, &dn);
|
||||
if (r < 0 && r != -EDESTADDRREQ) /* EDESTADDRREQ → just a file name was passed */
|
||||
return log_error_errno(r, "Failed to extract directory name from '%s': %m", src);
|
||||
|
||||
r = path_extract_filename(src, &fn);
|
||||
r = path_split_prefix_filename(src, &dn, &fn);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to extract file name from '%s': %m", src);
|
||||
return log_error_errno(r, "Failed to split '%s' into directory prefix and filename: %m", src);
|
||||
if (r == O_DIRECTORY)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EISDIR), "Expected path to regular file name, but got '%s', refusing.", src);
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "discover-image.h"
|
||||
#include "log.h"
|
||||
#include "mountpoint-util.h"
|
||||
#include "runtime-scope.h"
|
||||
#include "snapshot-util.h"
|
||||
#include "signal-util.h"
|
||||
#include "tmpfile-util.h"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "runtime-scope.h"
|
||||
#include "shared-forward.h"
|
||||
|
||||
/* create_ephemeral_snapshot - create a snapshot of the given directory.
|
||||
*
|
||||
|
||||
@@ -291,17 +291,15 @@ int unit_file_resolve_symlink(
|
||||
dir, dir ? "/" : "", filename);
|
||||
|
||||
if (!dir) {
|
||||
r = path_extract_directory(filename, &_dir);
|
||||
if (r < 0)
|
||||
return r;
|
||||
dir = _dir;
|
||||
|
||||
r = path_extract_filename(filename, &_filename);
|
||||
r = path_split_prefix_filename(filename, &_dir, &_filename);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == O_DIRECTORY)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EISDIR),
|
||||
"Unexpected path to a directory \"%s\", refusing.", filename);
|
||||
|
||||
/* We validate that the path is absolute above, hence dir must be extractable. */
|
||||
dir = ASSERT_PTR(_dir);
|
||||
filename = _filename;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user