/*
 * Utility routines.
 *
 * Copyright (C) 2001 Erik Andersen
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
#include "internal_libreport.h"

/* Concatenate path and filename to new allocated buffer.
 * Add '/' only as needed (no duplicate // are produced).
 * If path is NULL, it is assumed to be "/".
 * filename should not be NULL.
 */
char *concat_path_file(const char *path, const char *filename)
{
	if (!path)
		path = "";
	const char *end = path + strlen(path);
	while (*filename == '/')
		filename++;
	return xasprintf("%s%s%s", path, (end != path && end[-1] != '/' ? "/" : ""), filename);
}

char *concat_path_basename(const char *path, const char *filename)
{
    char *abspath = realpath(filename, NULL);
    char *base = strrchr((abspath ? abspath : filename), '/');

    /* If realpath failed and filename is malicious (say, "/foo/.."),
     * we may end up tricked into doing some bad things. Don't allow that.
     */
    char buf[sizeof("tmp-"LIBREPORT_ISO_DATE_STRING_SAMPLE"-%lu")];
    if (base && base[1] != '\0' && base[1] != '.')
    {
        /* We have a slash and it's not "foo/" or "foo/.<something>" */
        base++;
    }
    else
    {
        sprintf(buf, "tmp-%s-%lu", iso_date_string(NULL), (long)getpid());
        base = buf;
    }
    char *name = concat_path_file(path, base);
    free(abspath);
    return name;
}

bool str_is_correct_filename(const char *str)
{
#define NOT_PRINTABLE(c) (c < ' ' || c == 0x7f)

    if (NOT_PRINTABLE(*str) || *str == '/' || *str == '\0')
        return false;
    ++str;

    if (*str == '\0')
        return *(str-1) != '.';
    if (NOT_PRINTABLE(*str) || *str == '/')
        return false;
    ++str;

    if (*str == '\0')
        return !(*(str-2) == '.' && *(str-1) == '.');
    if (NOT_PRINTABLE(*str) || *str == '/')
        return false;
    ++str;

    for (unsigned i = 0; *str != '\0' && i < 61; ++str, ++i)
        if (NOT_PRINTABLE(*str) || *str == '/')
            return false;

    return *str == '\0';

#undef NOT_PRINTABLE
}
