mirror of
https://github.com/systemd/systemd.git
synced 2025-03-19 22:50:17 +03:00
path-util: rework file_in_same_dir() on top of path_extract_directory()
Let's port one more over. Note that this changes behaviour of file_in_same_dir() in some regards. Specifically, a trailing slash of the input path will be treated differently: previously we'd operate below that dir then, instead of the parent. I think that makes little sense however, and I think the code using this function doesn't expect that either. Moroever, addresses some corner cases if the path is specified as "/" or ".", i.e. where e cannot extract a parent. These will now be treated as error, which I think is much cleaner.
This commit is contained in:
parent
5b532e14e3
commit
162f6477c6
@ -174,24 +174,18 @@ int readlink_value(const char *p, char **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int readlink_and_make_absolute(const char *p, char **r) {
|
||||
int readlink_and_make_absolute(const char *p, char **ret) {
|
||||
_cleanup_free_ char *target = NULL;
|
||||
char *k;
|
||||
int j;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
assert(r);
|
||||
assert(ret);
|
||||
|
||||
j = readlink_malloc(p, &target);
|
||||
if (j < 0)
|
||||
return j;
|
||||
r = readlink_malloc(p, &target);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
k = file_in_same_dir(p, target);
|
||||
if (!k)
|
||||
return -ENOMEM;
|
||||
|
||||
*r = k;
|
||||
return 0;
|
||||
return file_in_same_dir(p, target, ret);
|
||||
}
|
||||
|
||||
int chmod_and_chown_at(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid) {
|
||||
|
@ -1164,31 +1164,35 @@ bool path_is_normalized(const char *p) {
|
||||
return true;
|
||||
}
|
||||
|
||||
char *file_in_same_dir(const char *path, const char *filename) {
|
||||
char *e, *ret;
|
||||
size_t k;
|
||||
int file_in_same_dir(const char *path, const char *filename, char **ret) {
|
||||
_cleanup_free_ char *b = NULL;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(filename);
|
||||
assert(ret);
|
||||
|
||||
/* This removes the last component of path and appends
|
||||
* filename, unless the latter is absolute anyway or the
|
||||
* former isn't */
|
||||
/* This removes the last component of path and appends filename, unless the latter is absolute anyway
|
||||
* or the former isn't */
|
||||
|
||||
if (path_is_absolute(filename))
|
||||
return strdup(filename);
|
||||
b = strdup(filename);
|
||||
else {
|
||||
_cleanup_free_ char *dn = NULL;
|
||||
|
||||
e = strrchr(path, '/');
|
||||
if (!e)
|
||||
return strdup(filename);
|
||||
r = path_extract_directory(path, &dn);
|
||||
if (r == -EDESTADDRREQ) /* no path prefix */
|
||||
b = strdup(filename);
|
||||
else if (r < 0)
|
||||
return r;
|
||||
else
|
||||
b = path_join(dn, filename);
|
||||
}
|
||||
if (!b)
|
||||
return -ENOMEM;
|
||||
|
||||
k = strlen(filename);
|
||||
ret = new(char, (e + 1 - path) + k + 1);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1);
|
||||
return ret;
|
||||
*ret = TAKE_PTR(b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool hidden_or_backup_file(const char *filename) {
|
||||
|
@ -170,7 +170,7 @@ static inline bool path_is_safe(const char *p) {
|
||||
}
|
||||
bool path_is_normalized(const char *p) _pure_;
|
||||
|
||||
char *file_in_same_dir(const char *path, const char *filename);
|
||||
int file_in_same_dir(const char *path, const char *filename, char **ret);
|
||||
|
||||
bool hidden_or_backup_file(const char *filename) _pure_;
|
||||
|
||||
|
@ -4681,13 +4681,13 @@ static int load_settings(void) {
|
||||
* actual image we shall boot. */
|
||||
|
||||
if (arg_image) {
|
||||
p = file_in_same_dir(arg_image, arg_settings_filename);
|
||||
if (!p)
|
||||
return log_oom();
|
||||
} else if (arg_directory && !path_equal(arg_directory, "/")) {
|
||||
p = file_in_same_dir(arg_directory, arg_settings_filename);
|
||||
if (!p)
|
||||
return log_oom();
|
||||
r = file_in_same_dir(arg_image, arg_settings_filename, &p);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to generate settings path from image path: %m");
|
||||
} else if (arg_directory) {
|
||||
r = file_in_same_dir(arg_directory, arg_settings_filename, &p);
|
||||
if (r < 0 && r != -EADDRNOTAVAIL) /* if directory is root fs, don't complain */
|
||||
return log_error_errno(r, "Failed to generate settings path from directory path: %m");
|
||||
}
|
||||
|
||||
if (p) {
|
||||
|
@ -85,8 +85,9 @@ DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(image_hash_ops, char, string_hash_func, st
|
||||
|
||||
static char **image_settings_path(Image *image) {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
const char *fn;
|
||||
unsigned i = 0;
|
||||
_cleanup_free_ char *fn = NULL;
|
||||
size_t i = 0;
|
||||
int r;
|
||||
|
||||
assert(image);
|
||||
|
||||
@ -94,7 +95,9 @@ static char **image_settings_path(Image *image) {
|
||||
if (!l)
|
||||
return NULL;
|
||||
|
||||
fn = strjoina(image->name, ".nspawn");
|
||||
fn = strjoin(image->name, ".nspawn");
|
||||
if (!fn)
|
||||
return NULL;
|
||||
|
||||
FOREACH_STRING(s, "/etc/systemd/nspawn", "/run/systemd/nspawn") {
|
||||
l[i] = path_join(s, fn);
|
||||
@ -104,21 +107,27 @@ static char **image_settings_path(Image *image) {
|
||||
i++;
|
||||
}
|
||||
|
||||
l[i] = file_in_same_dir(image->path, fn);
|
||||
if (!l[i])
|
||||
r = file_in_same_dir(image->path, fn, l + i);
|
||||
if (r == -ENOMEM)
|
||||
return NULL;
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to generate .nspawn settings path from image path, ignoring: %m");
|
||||
|
||||
strv_uniq(l);
|
||||
|
||||
return TAKE_PTR(l);
|
||||
}
|
||||
|
||||
static char *image_roothash_path(Image *image) {
|
||||
const char *fn;
|
||||
static int image_roothash_path(Image *image, char **ret) {
|
||||
_cleanup_free_ char *fn = NULL;
|
||||
|
||||
assert(image);
|
||||
|
||||
fn = strjoina(image->name, ".roothash");
|
||||
fn = strjoin(image->name, ".roothash");
|
||||
if (!fn)
|
||||
return -ENOMEM;
|
||||
|
||||
return file_in_same_dir(image->path, fn);
|
||||
return file_in_same_dir(image->path, fn, ret);
|
||||
}
|
||||
|
||||
static int image_new(
|
||||
@ -646,9 +655,9 @@ int image_remove(Image *i) {
|
||||
if (!settings)
|
||||
return -ENOMEM;
|
||||
|
||||
roothash = image_roothash_path(i);
|
||||
if (!roothash)
|
||||
return -ENOMEM;
|
||||
r = image_roothash_path(i, &roothash);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Make sure we don't interfere with a running nspawn */
|
||||
r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
|
||||
@ -708,15 +717,17 @@ int image_remove(Image *i) {
|
||||
}
|
||||
|
||||
static int rename_auxiliary_file(const char *path, const char *new_name, const char *suffix) {
|
||||
_cleanup_free_ char *rs = NULL;
|
||||
const char *fn;
|
||||
_cleanup_free_ char *fn = NULL, *rs = NULL;
|
||||
int r;
|
||||
|
||||
fn = strjoina(new_name, suffix);
|
||||
|
||||
rs = file_in_same_dir(path, fn);
|
||||
if (!rs)
|
||||
fn = strjoin(new_name, suffix);
|
||||
if (!fn)
|
||||
return -ENOMEM;
|
||||
|
||||
r = file_in_same_dir(path, fn, &rs);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return rename_noreplace(AT_FDCWD, path, AT_FDCWD, rs);
|
||||
}
|
||||
|
||||
@ -739,9 +750,9 @@ int image_rename(Image *i, const char *new_name) {
|
||||
if (!settings)
|
||||
return -ENOMEM;
|
||||
|
||||
roothash = image_roothash_path(i);
|
||||
if (!roothash)
|
||||
return -ENOMEM;
|
||||
r = image_roothash_path(i, &roothash);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Make sure we don't interfere with a running nspawn */
|
||||
r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
|
||||
@ -772,7 +783,7 @@ int image_rename(Image *i, const char *new_name) {
|
||||
|
||||
_fallthrough_;
|
||||
case IMAGE_SUBVOLUME:
|
||||
new_path = file_in_same_dir(i->path, new_name);
|
||||
r = file_in_same_dir(i->path, new_name, &new_path);
|
||||
break;
|
||||
|
||||
case IMAGE_BLOCK:
|
||||
@ -781,23 +792,23 @@ int image_rename(Image *i, const char *new_name) {
|
||||
if (path_startswith(i->path, "/dev"))
|
||||
return -EROFS;
|
||||
|
||||
new_path = file_in_same_dir(i->path, new_name);
|
||||
r = file_in_same_dir(i->path, new_name, &new_path);
|
||||
break;
|
||||
|
||||
case IMAGE_RAW: {
|
||||
const char *fn;
|
||||
|
||||
fn = strjoina(new_name, ".raw");
|
||||
new_path = file_in_same_dir(i->path, fn);
|
||||
|
||||
r = file_in_same_dir(i->path, fn, &new_path);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (!new_path)
|
||||
return -ENOMEM;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
nn = strdup(new_name);
|
||||
if (!nn)
|
||||
@ -828,15 +839,17 @@ int image_rename(Image *i, const char *new_name) {
|
||||
}
|
||||
|
||||
static int clone_auxiliary_file(const char *path, const char *new_name, const char *suffix) {
|
||||
_cleanup_free_ char *rs = NULL;
|
||||
const char *fn;
|
||||
_cleanup_free_ char *fn = NULL, *rs = NULL;
|
||||
int r;
|
||||
|
||||
fn = strjoina(new_name, suffix);
|
||||
|
||||
rs = file_in_same_dir(path, fn);
|
||||
if (!rs)
|
||||
fn = strjoin(new_name, suffix);
|
||||
if (!fn)
|
||||
return -ENOMEM;
|
||||
|
||||
r = file_in_same_dir(path, fn, &rs);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return copy_file_atomic(path, rs, 0664, 0, 0, COPY_REFLINK);
|
||||
}
|
||||
|
||||
@ -856,9 +869,9 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
|
||||
if (!settings)
|
||||
return -ENOMEM;
|
||||
|
||||
roothash = image_roothash_path(i);
|
||||
if (!roothash)
|
||||
return -ENOMEM;
|
||||
r = image_roothash_path(i, &roothash);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Make sure nobody takes the new name, between the time we
|
||||
* checked it is currently unused in all search paths, and the
|
||||
|
@ -600,23 +600,19 @@ TEST(prefix_root) {
|
||||
TEST(file_in_same_dir) {
|
||||
char *t;
|
||||
|
||||
t = file_in_same_dir("/", "a");
|
||||
assert_se(file_in_same_dir("/", "a", &t) == -EADDRNOTAVAIL);
|
||||
|
||||
assert_se(file_in_same_dir("/", "/a", &t) >= 0);
|
||||
assert_se(streq(t, "/a"));
|
||||
free(t);
|
||||
|
||||
t = file_in_same_dir("/", "/a");
|
||||
assert_se(streq(t, "/a"));
|
||||
assert_se(file_in_same_dir("", "a", &t) == -EINVAL);
|
||||
|
||||
assert_se(file_in_same_dir("a/", "x", &t) >= 0);
|
||||
assert_se(streq(t, "x"));
|
||||
free(t);
|
||||
|
||||
t = file_in_same_dir("", "a");
|
||||
assert_se(streq(t, "a"));
|
||||
free(t);
|
||||
|
||||
t = file_in_same_dir("a/", "a");
|
||||
assert_se(streq(t, "a/a"));
|
||||
free(t);
|
||||
|
||||
t = file_in_same_dir("bar/foo", "bar");
|
||||
assert_se(file_in_same_dir("bar/foo", "bar", &t) >= 0);
|
||||
assert_se(streq(t, "bar/bar"));
|
||||
free(t);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user