view th_file.c @ 457:85fa3d333556

Actually, revert the boolean changes .. meh.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 02 Jan 2018 23:09:29 +0200
parents 347bfd3e017e
children 77d1af382e08
line wrap: on
line source

/*
 * File, directory etc helper functions
 * Programmed and designed by Matti 'ccr' Hamalainen
 * (C) Copyright 2016-2018 Tecnic Software productions (TNSP)
 *
 * Please read file 'COPYING' for information on license and distribution.
 */
#include "th_file.h"
#include "th_string.h"
#include <unistd.h>
//#include <fcntl.h>
#ifdef TH_PLAT_WINDOWS
#  include <shlwapi.h>
#  include <shfolder.h>
#else
//#  include <sys/wait.h>
#  include <sys/stat.h>
#  include <sys/types.h>
#endif


char * th_get_home_dir()
{
#if defined(TH_PLAT_WINDOWS)
    char tmpPath[MAX_PATH];
    if (SHGetFolderPath(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, tmpPath) == S_OK)
        return th_strdup(tmpPath);
#endif
    return th_strdup(getenv("HOME"));
}


char * th_get_data_dir()
{
#if defined(TH_PLAT_WINDOWS)
    char tmpPath[MAX_PATH];
    if (SHGetFolderPath(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, tmpPath) == S_OK)
        return th_strdup(tmpPath);
#endif
    return th_strdup(getenv("HOME"));
}


char * th_get_config_dir(const char *name)
{
#if defined(TH_PLAT_WINDOWS)
    // For Windows, we just use the appdata directory
    (void) name;
    return th_get_data_dir();
#elif defined(USE_XDG)
    const char *xdgConfigDir = getenv("XDG_CONFIG_HOME");

    // If XDG is enabled, try the environment variable first
    if (xdgConfigDir != NULL && strcmp(xdgConfigDir, ""))
        return th_strdup_printf("%s%c%s%c", xdgConfigDir, TH_DIR_SEPARATOR, name, TH_DIR_SEPARATOR);
    else
    {
        // Nope, try the obvious alternative
        char *data = th_get_data_dir();
        char *dir = th_strdup_printf("%s%c%s%c%s%c", data, TH_DIR_SEPARATOR, ".config", TH_DIR_SEPARATOR, name, TH_DIR_SEPARATOR);
        th_free(data);
        return dir;
    }
#else
    // XDG not enabled
    (void) name;
    return th_get_data_dir();
#endif
}


BOOL th_stat_path(const char *path, int *flags)
{
    *flags = 0;

#ifdef TH_PLAT_WINDOWS
    DWORD attr = GetFileAttributes(path);

    *flags |= (attr & FILE_ATTRIBUTE_DIRECTORY) ? TH_IS_DIR : 0;
    *flags |= (attr & FILE_ATTRIBUTE_READONLY) ? 0 : TH_IS_WRITABLE;
    *flags |= TH_IS_READABLE;
#else
    uid_t id = geteuid();
    struct stat sb;
    if (stat(path, &sb) < 0)
        return FALSE;

    *flags |= S_ISDIR(sb.st_mode) ? TH_IS_DIR : 0;
    *flags |= (id == sb.st_uid && (sb.st_mode & S_IWUSR)) ? TH_IS_WRITABLE : 0;
    *flags |= (id == sb.st_uid && (sb.st_mode & S_IRUSR)) ? TH_IS_READABLE : 0;
#endif

    return TRUE;
}


BOOL th_mkdir_path(const char *cpath, int mode)
{
    char save, *path = th_strdup(cpath);
    size_t start = 0, end;
    BOOL res = FALSE;

    // If mode is 0, default to something sensible
    if (mode == 0)
        mode = 0711;

    // Start creating the directory stucture
    do
    {
        // Split foremost path element out
        for (save = 0, end = start; path[end] != 0; end++)
        if (path[end] == TH_DIR_SEPARATOR)
        {
            save = path[end];
            path[end] = 0;
            break;
        }

        // If the element is there, create it
        if (path[start] != 0)
        {
            int flags;
            BOOL exists = th_stat_path(path, &flags);
            if (exists && (flags & TH_IS_DIR) == 0)
                goto error;

            if (!exists)
            {
#ifdef TH_PLAT_WINDOWS
                if (!CreateDirectory(path, NULL))
                    goto error;
#else
                if (mkdir(path, mode) < 0)
                    goto error;
#endif
            }
        }

        // Restore separator character and jump to next element
        path[end] = save;
        start = end + 1;
    } while (save != 0);

    res = TRUE;

error:
    th_free(path);
    return res;
}