tmpfile-util: truncate original filename if the result filename is too long
This also verify that the extra string does not contain '/'.
This commit is contained in:
+74
-73
@@ -86,12 +86,76 @@ int fmkostemp_safe(char *pattern, const char *mode, FILE **ret_f) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
|
||||
_cleanup_free_ char *d = NULL, *fn = NULL, *nf = NULL;
|
||||
static int tempfn_build(const char *p, const char *pre, const char *post, bool child, char **ret) {
|
||||
_cleanup_free_ char *d = NULL, *fn = NULL, *nf = NULL, *result = NULL;
|
||||
size_t len_pre, len_post, len_add;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
assert(ret);
|
||||
|
||||
/*
|
||||
* Turns this:
|
||||
* /foo/bar/waldo
|
||||
*
|
||||
* Into this :
|
||||
* /foo/bar/waldo/.#<pre><post> (child == true)
|
||||
* /foo/bar/.#<pre>waldo<post> (child == false)
|
||||
*/
|
||||
|
||||
if (pre && strchr(pre, '/'))
|
||||
return -EINVAL;
|
||||
|
||||
if (post && strchr(post, '/'))
|
||||
return -EINVAL;
|
||||
|
||||
len_pre = strlen_ptr(pre);
|
||||
len_post = strlen_ptr(post);
|
||||
/* NAME_MAX is counted *without* the trailing NUL byte. */
|
||||
if (len_pre > NAME_MAX - STRLEN(".#") ||
|
||||
len_post > NAME_MAX - STRLEN(".#") - len_pre)
|
||||
return -EINVAL;
|
||||
|
||||
len_add = len_pre + len_post + STRLEN(".#");
|
||||
|
||||
if (child) {
|
||||
d = strdup(p);
|
||||
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);
|
||||
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';
|
||||
}
|
||||
|
||||
nf = strjoin(".#", strempty(pre), strempty(fn), strempty(post));
|
||||
if (!nf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (d) {
|
||||
if (!path_extend(&d, nf))
|
||||
return -ENOMEM;
|
||||
|
||||
result = path_simplify(TAKE_PTR(d));
|
||||
} else
|
||||
result = TAKE_PTR(nf);
|
||||
|
||||
if (!path_is_valid(result)) /* New path is not valid? (Maybe because too long?) Refuse. */
|
||||
return -EINVAL;
|
||||
|
||||
*ret = TAKE_PTR(result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
|
||||
/*
|
||||
* Turns this:
|
||||
* /foo/bar/waldo
|
||||
@@ -100,36 +164,13 @@ int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
|
||||
* /foo/bar/.#<extra>waldoXXXXXX
|
||||
*/
|
||||
|
||||
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);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
nf = strjoin(".#", strempty(extra), fn, "XXXXXX");
|
||||
if (!nf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!filename_is_valid(nf)) /* New name is not valid? (Maybe because too long?) Refuse. */
|
||||
return -EINVAL;
|
||||
|
||||
if (d) {
|
||||
if (!path_extend(&d, nf))
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = path_simplify(TAKE_PTR(d));
|
||||
} else
|
||||
*ret = TAKE_PTR(nf);
|
||||
|
||||
return 0;
|
||||
return tempfn_build(p, extra, "XXXXXX", /* child = */ false, ret);
|
||||
}
|
||||
|
||||
int tempfn_random(const char *p, const char *extra, char **ret) {
|
||||
_cleanup_free_ char *d = NULL, *fn = NULL, *nf = NULL;
|
||||
int r;
|
||||
_cleanup_free_ char *s = NULL;
|
||||
|
||||
assert(p);
|
||||
assert(ret);
|
||||
|
||||
/*
|
||||
@@ -140,37 +181,14 @@ int tempfn_random(const char *p, const char *extra, char **ret) {
|
||||
* /foo/bar/.#<extra>waldobaa2a261115984a9
|
||||
*/
|
||||
|
||||
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);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (asprintf(&nf, ".#%s%s%016" PRIx64,
|
||||
strempty(extra),
|
||||
fn,
|
||||
random_u64()) < 0)
|
||||
if (asprintf(&s, "%016" PRIx64, random_u64()) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!filename_is_valid(nf)) /* Not valid? (maybe because too long now?) — refuse early */
|
||||
return -EINVAL;
|
||||
|
||||
if (d) {
|
||||
if (!path_extend(&d, nf))
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = path_simplify(TAKE_PTR(d));
|
||||
} else
|
||||
*ret = TAKE_PTR(nf);
|
||||
|
||||
return 0;
|
||||
return tempfn_build(p, extra, s, /* child = */ false, ret);
|
||||
}
|
||||
|
||||
int tempfn_random_child(const char *p, const char *extra, char **ret) {
|
||||
char *t, *x;
|
||||
uint64_t u;
|
||||
_cleanup_free_ char *s = NULL;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
@@ -187,27 +205,10 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) {
|
||||
return r;
|
||||
}
|
||||
|
||||
extra = strempty(extra);
|
||||
|
||||
t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1);
|
||||
if (!t)
|
||||
if (asprintf(&s, "%016" PRIx64, random_u64()) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
if (isempty(p))
|
||||
x = stpcpy(stpcpy(t, ".#"), extra);
|
||||
else
|
||||
x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
|
||||
|
||||
u = random_u64();
|
||||
for (unsigned i = 0; i < 16; i++) {
|
||||
*(x++) = hexchar(u & 0xF);
|
||||
u >>= 4;
|
||||
}
|
||||
|
||||
*x = 0;
|
||||
|
||||
*ret = path_simplify(t);
|
||||
return 0;
|
||||
return tempfn_build(p, extra, s, /* child = */ true, ret);
|
||||
}
|
||||
|
||||
int open_tmpfile_unlinkable(const char *directory, int flags) {
|
||||
|
||||
Reference in New Issue
Block a user