replaced strndupcat with path_append, added LinkTable_disk_*() functions
This commit is contained in:
parent
825bd4d3fb
commit
9a5f37d91f
44
src/cache.c
44
src/cache.c
|
@ -27,12 +27,6 @@
|
|||
*/
|
||||
#define MAX_SEGBC 1073741824
|
||||
|
||||
/**
|
||||
* \brief the maximum length of a path
|
||||
* \details This corresponds the maximum path length under Ext4.
|
||||
*/
|
||||
#define MAX_PATH_LEN 4096
|
||||
|
||||
/**
|
||||
* \brief error associated with metadata
|
||||
*/
|
||||
|
@ -77,11 +71,11 @@ void CacheSystem_init(const char *path)
|
|||
|
||||
/* Handle the case of missing '/' */
|
||||
if (path[strnlen(path, MAX_PATH_LEN) - 1] == '/') {
|
||||
META_DIR = strndupcat(path, "meta/", MAX_PATH_LEN);
|
||||
DATA_DIR = strndupcat(path, "data/", MAX_PATH_LEN);
|
||||
META_DIR = path_append(path, "meta/");
|
||||
DATA_DIR = path_append(path, "data/");
|
||||
} else {
|
||||
META_DIR = strndupcat(path, "/meta/", MAX_PATH_LEN);
|
||||
DATA_DIR = strndupcat(path, "/data/", MAX_PATH_LEN);
|
||||
META_DIR = path_append(path, "/meta/");
|
||||
DATA_DIR = path_append(path, "/data/");
|
||||
}
|
||||
|
||||
/* Check if directories exist, if not, create them */
|
||||
|
@ -235,7 +229,7 @@ static int Data_create(Cache *cf)
|
|||
int mode;
|
||||
|
||||
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||
char *datafn = strndupcat(DATA_DIR, cf->path, MAX_PATH_LEN);
|
||||
char *datafn = path_append(DATA_DIR, cf->path);
|
||||
fd = open(datafn, O_WRONLY | O_CREAT, mode);
|
||||
free(datafn);
|
||||
if (fd == -1) {
|
||||
|
@ -256,7 +250,7 @@ static int Data_create(Cache *cf)
|
|||
*/
|
||||
static long Data_size(const char *fn)
|
||||
{
|
||||
char *datafn = strndupcat(DATA_DIR, fn, MAX_PATH_LEN);
|
||||
char *datafn = path_append(DATA_DIR, fn);
|
||||
struct stat st;
|
||||
int s = stat(datafn, &st);
|
||||
free(datafn);
|
||||
|
@ -341,11 +335,6 @@ static long Data_write(Cache *cf, const uint8_t *buf, off_t len,
|
|||
fprintf(stderr,
|
||||
"Data_write(): fwrite(): requested %ld, returned %ld!\n",
|
||||
len, byte_written);
|
||||
if (feof(cf->dfp)) {
|
||||
/* reached EOF */
|
||||
fprintf(stderr,
|
||||
"Data_write(): fwrite(): reached the end of the file!\n");
|
||||
}
|
||||
if (ferror(cf->dfp)) {
|
||||
/* filesystem error */
|
||||
fprintf(stderr,
|
||||
|
@ -358,8 +347,8 @@ static long Data_write(Cache *cf, const uint8_t *buf, off_t len,
|
|||
|
||||
int CacheDir_create(const char *dirn)
|
||||
{
|
||||
char *metadirn = strndupcat(META_DIR, dirn, MAX_PATH_LEN);
|
||||
char *datadirn = strndupcat(DATA_DIR, dirn, MAX_PATH_LEN);
|
||||
char *metadirn = path_append(META_DIR, dirn);
|
||||
char *datadirn = path_append(DATA_DIR, dirn);
|
||||
int i;
|
||||
|
||||
i = -mkdir(metadirn, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
|
@ -461,8 +450,8 @@ static int Cache_exist(const char *fn)
|
|||
{
|
||||
int meta_exists = 1;
|
||||
int data_exists = 1;
|
||||
char *metafn = strndupcat(META_DIR, fn, MAX_PATH_LEN);
|
||||
char *datafn = strndupcat(DATA_DIR, fn, MAX_PATH_LEN);
|
||||
char *metafn = path_append(META_DIR, fn);
|
||||
char *datafn = path_append(DATA_DIR, fn);
|
||||
|
||||
if (access(metafn, F_OK)) {
|
||||
// fprintf(stderr, "Cache_exist(): access(): %s\n", strerror(errno));
|
||||
|
@ -501,8 +490,8 @@ static int Cache_exist(const char *fn)
|
|||
void Cache_delete(const char *fn)
|
||||
{
|
||||
// fprintf(stderr, "Cache_delete(): deleting %s\n", fn);
|
||||
char *metafn = strndupcat(META_DIR, fn, MAX_PATH_LEN);
|
||||
char *datafn = strndupcat(DATA_DIR, fn, MAX_PATH_LEN);
|
||||
char *metafn = path_append(META_DIR, fn);
|
||||
char *datafn = path_append(DATA_DIR, fn);
|
||||
if (!access(metafn, F_OK)) {
|
||||
if(unlink(metafn)) {
|
||||
fprintf(stderr, "Cache_delete(): unlink(): %s\n",
|
||||
|
@ -528,12 +517,13 @@ void Cache_delete(const char *fn)
|
|||
*/
|
||||
static int Data_open(Cache *cf)
|
||||
{
|
||||
char *datafn = strndupcat(DATA_DIR, cf->path, MAX_PATH_LEN);
|
||||
char *datafn = path_append(DATA_DIR, cf->path);
|
||||
cf->dfp = fopen(datafn, "r+");
|
||||
free(datafn);
|
||||
if (!cf->dfp) {
|
||||
/* Failed to open the data file */
|
||||
fprintf(stderr, "Data_open(): fopen(): %s\n", strerror(errno));
|
||||
fprintf(stderr, "Data_open(): fopen(%s): %s\n", datafn,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -547,7 +537,7 @@ static int Data_open(Cache *cf)
|
|||
*/
|
||||
static int Meta_open(Cache *cf)
|
||||
{
|
||||
char *metafn = strndupcat(META_DIR, cf->path, MAX_PATH_LEN);
|
||||
char *metafn = path_append(META_DIR, cf->path);
|
||||
cf->mfp = fopen(metafn, "r+");
|
||||
if (!cf->mfp) {
|
||||
/* Failed to open the data file */
|
||||
|
@ -568,7 +558,7 @@ static int Meta_open(Cache *cf)
|
|||
*/
|
||||
static int Meta_create(Cache *cf)
|
||||
{
|
||||
char *metafn = strndupcat(META_DIR, cf->path, MAX_PATH_LEN);
|
||||
char *metafn = path_append(META_DIR, cf->path);
|
||||
cf->mfp = fopen(metafn, "w");
|
||||
if (!cf->mfp) {
|
||||
/* Failed to open the data file */
|
||||
|
|
142
src/link.c
142
src/link.c
|
@ -37,11 +37,11 @@ static Link *Link_new(const char *linkname, LinkType type)
|
|||
fprintf(stderr, "Link_new(): calloc failure!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
strncpy(link->linkname, linkname, LINKNAME_LEN_MAX);
|
||||
strncpy(link->linkname, linkname, MAX_FILENAME_LEN);
|
||||
link->type = type;
|
||||
|
||||
/* remove the '/' from linkname if it exists */
|
||||
char *c = &(link->linkname[strnlen(link->linkname, LINKNAME_LEN_MAX) - 1]);
|
||||
char *c = &(link->linkname[strnlen(link->linkname, MAX_FILENAME_LEN) - 1]);
|
||||
if ( *c == '/') {
|
||||
*c = '\0';
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ static LinkType linkname_type(const char *linkname)
|
|||
return LINK_INVALID;
|
||||
}
|
||||
|
||||
if ( linkname[strnlen(linkname, LINKNAME_LEN_MAX) - 1] == '/' ) {
|
||||
if ( linkname[strnlen(linkname, MAX_FILENAME_LEN) - 1] == '/' ) {
|
||||
return LINK_DIR;
|
||||
}
|
||||
|
||||
|
@ -185,29 +185,6 @@ void Link_set_stat(Link* this_link, CURL *curl)
|
|||
}
|
||||
}
|
||||
|
||||
static char *url_append(const char *url, const char *sublink)
|
||||
{
|
||||
int needs_separator = 0;
|
||||
if (url[strnlen(url, URL_LEN_MAX)-1] != '/') {
|
||||
needs_separator = 1;
|
||||
}
|
||||
|
||||
char *str;
|
||||
size_t ul = strnlen(url, URL_LEN_MAX);
|
||||
size_t sl = strnlen(sublink, LINKNAME_LEN_MAX);
|
||||
str = calloc(ul + sl + needs_separator + 1, sizeof(char));
|
||||
if (!str) {
|
||||
fprintf(stderr, "url_append(): calloc failure!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
strncpy(str, url, ul);
|
||||
if (needs_separator) {
|
||||
str[ul] = '/';
|
||||
}
|
||||
strncat(str, sublink, sl);
|
||||
return str;
|
||||
}
|
||||
|
||||
static void LinkTable_fill(LinkTable *linktbl)
|
||||
{
|
||||
Link *head_link = linktbl->links[0];
|
||||
|
@ -215,14 +192,14 @@ static void LinkTable_fill(LinkTable *linktbl)
|
|||
Link *this_link = linktbl->links[i];
|
||||
if (this_link->type) {
|
||||
char *url;
|
||||
url = url_append(head_link->f_url, this_link->linkname);
|
||||
strncpy(this_link->f_url, url, URL_LEN_MAX);
|
||||
url = path_append(head_link->f_url, this_link->linkname);
|
||||
strncpy(this_link->f_url, url, MAX_PATH_LEN);
|
||||
free(url);
|
||||
|
||||
char *unescaped_linkname;
|
||||
unescaped_linkname = curl_easy_unescape(NULL, this_link->linkname, 0,
|
||||
NULL);
|
||||
strncpy(this_link->linkname, unescaped_linkname, LINKNAME_LEN_MAX);
|
||||
strncpy(this_link->linkname, unescaped_linkname, MAX_FILENAME_LEN);
|
||||
curl_free(unescaped_linkname);
|
||||
|
||||
if (this_link->type == LINK_FILE && !(this_link->content_length)) {
|
||||
|
@ -281,7 +258,7 @@ LinkTable *LinkTable_new(const char *url)
|
|||
LinkTable_add(linktbl, Link_new("/", LINK_HEAD));
|
||||
Link *head_link = linktbl->links[0];
|
||||
head_link->type = LINK_HEAD;
|
||||
strncpy(head_link->f_url, url, URL_LEN_MAX);
|
||||
strncpy(head_link->f_url, url, MAX_PATH_LEN);
|
||||
|
||||
/* start downloading the base URL */
|
||||
CURL *curl = Link_to_curl(head_link);
|
||||
|
@ -327,6 +304,103 @@ URL: %s, HTTP %ld\n", url, http_resp);
|
|||
return linktbl;
|
||||
}
|
||||
|
||||
static void LinkTable_disk_delete(const char *dirn)
|
||||
{
|
||||
char *path = path_append(dirn, ".LinkTable");
|
||||
if(unlink(path)) {
|
||||
fprintf(stderr, "LinkTable_delete(): unlink(): %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
free(path);
|
||||
}
|
||||
|
||||
int LinkTable_disk_save(LinkTable *linktbl, const char *dirn)
|
||||
{
|
||||
char *path = path_append(dirn, ".LinkTable");
|
||||
FILE *fp = fopen(path, "w");
|
||||
free(path);
|
||||
|
||||
if (!fp) {
|
||||
fprintf(stderr, "LinkTable_save(): fopen(): %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
fwrite(&linktbl->num, sizeof(int), 1, fp);
|
||||
for (int i = 0; i < linktbl->num; i++) {
|
||||
fwrite(linktbl->links[i]->linkname, sizeof(char), MAX_FILENAME_LEN, fp);
|
||||
fwrite(linktbl->links[i]->f_url, sizeof(char), MAX_PATH_LEN, fp);
|
||||
fwrite(&linktbl->links[i]->type, sizeof(LinkType), 1, fp);
|
||||
fwrite(&linktbl->links[i]->content_length, sizeof(size_t), 1, fp);
|
||||
fwrite(&linktbl->links[i]->time, sizeof(long), 1, fp);
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
|
||||
if (ferror(fp)) {
|
||||
fprintf(stderr, "LinkTable_save(): encountered ferror!\n");
|
||||
res = -1;
|
||||
}
|
||||
|
||||
if (fclose(fp)) {
|
||||
fprintf(stderr, "LinkTable_save(): cannot close the file pointer, %s\n",
|
||||
strerror(errno));
|
||||
res = -1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
LinkTable *LinkTable_disk_open(const char *dirn)
|
||||
{
|
||||
char *path = path_append(dirn, ".LinkTable");
|
||||
FILE *fp = fopen(path, "r");
|
||||
free(path);
|
||||
|
||||
if (!fp) {
|
||||
fprintf(stderr, "LinkTable_save(): fopen(): %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LinkTable *linktbl = calloc(1, sizeof(LinkTable));
|
||||
if (!linktbl) {
|
||||
fprintf(stderr, "LinkTable_open(): calloc linktbl failed!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fread(&linktbl->num, sizeof(int), 1, fp);
|
||||
linktbl->links = calloc(linktbl->num, sizeof(Link *));
|
||||
for (int i = 0; i < linktbl->num; i++) {
|
||||
linktbl->links[i] = calloc(1, sizeof(Link));
|
||||
if (linktbl->links[i]) {
|
||||
fprintf(stderr, "LinkTable_open(): calloc links[i] failed!\n");
|
||||
}
|
||||
fread(linktbl->links[i]->f_url, sizeof(char), MAX_PATH_LEN, fp);
|
||||
fread(&linktbl->links[i]->type, sizeof(LinkType), 1, fp);
|
||||
fread(&linktbl->links[i]->content_length, sizeof(size_t), 1, fp);
|
||||
fread(&linktbl->links[i]->time, sizeof(long), 1, fp);
|
||||
if (feof(fp)) {
|
||||
/* reached EOF */
|
||||
fprintf(stderr,
|
||||
"LinkTable_open(): reached EOF!\n");
|
||||
LinkTable_free(linktbl);
|
||||
LinkTable_disk_delete(dirn);
|
||||
return NULL;
|
||||
}
|
||||
if (ferror(fp)) {
|
||||
fprintf(stderr, "LinkTable_open(): encountered ferror!\n");
|
||||
LinkTable_free(linktbl);
|
||||
LinkTable_disk_delete(dirn);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (fclose(fp)) {
|
||||
fprintf(stderr, "LinkTable_save(): cannot close the file pointer, %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
return linktbl;
|
||||
}
|
||||
|
||||
|
||||
LinkTable *path_to_Link_LinkTable_new(const char *path)
|
||||
{
|
||||
Link *link = path_to_Link(path);
|
||||
|
@ -344,7 +418,7 @@ static Link *path_to_Link_recursive(char *path, LinkTable *linktbl)
|
|||
}
|
||||
|
||||
/* remove the last '/' if it exists */
|
||||
char *slash = &(path[strnlen(path, URL_LEN_MAX) - 1]);
|
||||
char *slash = &(path[strnlen(path, MAX_PATH_LEN) - 1]);
|
||||
if (*slash == '/') {
|
||||
*slash = '\0';
|
||||
}
|
||||
|
@ -353,7 +427,7 @@ static Link *path_to_Link_recursive(char *path, LinkTable *linktbl)
|
|||
if ( slash == NULL ) {
|
||||
/* We cannot find another '/', we have reached the last level */
|
||||
for (int i = 1; i < linktbl->num; i++) {
|
||||
if (!strncmp(path, linktbl->links[i]->linkname, LINKNAME_LEN_MAX)) {
|
||||
if (!strncmp(path, linktbl->links[i]->linkname, MAX_FILENAME_LEN)) {
|
||||
/* We found our link */
|
||||
return linktbl->links[i];
|
||||
}
|
||||
|
@ -372,7 +446,7 @@ static Link *path_to_Link_recursive(char *path, LinkTable *linktbl)
|
|||
/* move the pointer past the '/' */
|
||||
char *next_path = slash + 1;
|
||||
for (int i = 1; i < linktbl->num; i++) {
|
||||
if (!strncmp(path, linktbl->links[i]->linkname, LINKNAME_LEN_MAX)) {
|
||||
if (!strncmp(path, linktbl->links[i]->linkname, MAX_FILENAME_LEN)) {
|
||||
/* The next sub-directory exists */
|
||||
if (!linktbl->links[i]->next_table) {
|
||||
linktbl->links[i]->next_table = LinkTable_new(
|
||||
|
@ -388,7 +462,7 @@ static Link *path_to_Link_recursive(char *path, LinkTable *linktbl)
|
|||
|
||||
Link *path_to_Link(const char *path)
|
||||
{
|
||||
char *new_path = strndup(path, URL_LEN_MAX);
|
||||
char *new_path = strndup(path, MAX_PATH_LEN);
|
||||
if (!new_path) {
|
||||
fprintf(stderr, "path_to_Link(): cannot allocate memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
|
|
19
src/link.h
19
src/link.h
|
@ -1,12 +1,9 @@
|
|||
#ifndef LINK_H
|
||||
#define LINK_H
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include "util.h"
|
||||
|
||||
/** \brief the maximum length of the URL */
|
||||
#define URL_LEN_MAX 2048
|
||||
/** \brief the maximum length of a partial URL (a link) */
|
||||
#define LINKNAME_LEN_MAX 255
|
||||
#include <curl/curl.h>
|
||||
|
||||
/** \brief the link type */
|
||||
typedef enum {
|
||||
|
@ -29,9 +26,9 @@ typedef struct Link Link;
|
|||
* \brief Link data structure
|
||||
*/
|
||||
struct Link {
|
||||
char linkname[LINKNAME_LEN_MAX]; /**< The link name in the last level of
|
||||
char linkname[MAX_FILENAME_LEN]; /**< The link name in the last level of
|
||||
the URL */
|
||||
char f_url[URL_LEN_MAX]; /**< The full URL of the file */
|
||||
char f_url[MAX_PATH_LEN]; /**< The full URL of the file */
|
||||
LinkType type; /**< The type of the link */
|
||||
size_t content_length; /**< CURLINFO_CONTENT_LENGTH_DOWNLOAD of the file */
|
||||
LinkTable *next_table; /**< The next LinkTable level, if it is a LINK_DIR */
|
||||
|
@ -80,5 +77,13 @@ Link *path_to_Link(const char *path);
|
|||
*/
|
||||
LinkTable *path_to_Link_LinkTable_new(const char *path);
|
||||
|
||||
/**
|
||||
* \brief dump a link table to the disk.
|
||||
*/
|
||||
int LinkTable_disk_save(LinkTable *linktbl, const char *dirn);
|
||||
|
||||
/**
|
||||
* \brief load a link table from the disk.
|
||||
*/
|
||||
LinkTable *LinkTable_disk_open(const char *dirn);
|
||||
#endif
|
||||
|
|
|
@ -98,7 +98,7 @@ void parse_config_file(char ***argv, int *argc)
|
|||
strncat(full_path, main_config_name, strlen(main_config_name));
|
||||
|
||||
/* The buffer has to be able to fit a URL */
|
||||
int buf_len = URL_LEN_MAX;
|
||||
int buf_len = MAX_PATH_LEN;
|
||||
char buf[buf_len];
|
||||
FILE *config = fopen(full_path, "r");
|
||||
if (config) {
|
||||
|
@ -178,7 +178,7 @@ parse_arg_list(int argc, char **argv, char ***fuse_argv, int *fuse_argc)
|
|||
NETWORK_CONFIG.password = strndup(optarg, ARG_LEN_MAX);
|
||||
break;
|
||||
case 'P':
|
||||
NETWORK_CONFIG.proxy = strndup(optarg, URL_LEN_MAX);
|
||||
NETWORK_CONFIG.proxy = strndup(optarg, MAX_PATH_LEN);
|
||||
break;
|
||||
case 'L':
|
||||
/* Long options */
|
||||
|
|
|
@ -263,7 +263,7 @@ LinkTable *network_init(const char *url)
|
|||
|
||||
/* --------- Set the length of the root link ----------- */
|
||||
/* This is where the '/' should be */
|
||||
ROOT_LINK_OFFSET = strnlen(url, URL_LEN_MAX) - 1;
|
||||
ROOT_LINK_OFFSET = strnlen(url, MAX_PATH_LEN) - 1;
|
||||
if (url[ROOT_LINK_OFFSET] != '/') {
|
||||
/*
|
||||
* If '/' is not there, it is automatically added, so we need to skip 2
|
||||
|
|
36
src/util.c
36
src/util.c
|
@ -4,29 +4,27 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
char *strndupcat(const char *a, const char *b, int n)
|
||||
char *path_append(const char *path, const char *filename)
|
||||
{
|
||||
int na = strnlen(a, n);
|
||||
int nb = strnlen(b, n);
|
||||
int nc = na + nb + 1;
|
||||
if (nc > n) {
|
||||
fprintf(stderr,
|
||||
"strndupcat(): resulting string length exceeds maximum limit!\n");
|
||||
/*
|
||||
* It is better to crash the program here, then corrupting the cache
|
||||
* folder
|
||||
*/
|
||||
int needs_separator = 0;
|
||||
if (path[strnlen(path, MAX_PATH_LEN)-1] != '/') {
|
||||
needs_separator = 1;
|
||||
}
|
||||
|
||||
char *str;
|
||||
size_t ul = strnlen(path, MAX_PATH_LEN);
|
||||
size_t sl = strnlen(filename, MAX_FILENAME_LEN);
|
||||
str = calloc(ul + sl + needs_separator + 1, sizeof(char));
|
||||
if (!str) {
|
||||
fprintf(stderr, "path_append(): calloc failure!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
char *c = calloc(nc, sizeof(char));
|
||||
if (!c) {
|
||||
fprintf(stderr, "strndupcat(): calloc failure!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
strncpy(str, path, ul);
|
||||
if (needs_separator) {
|
||||
str[ul] = '/';
|
||||
}
|
||||
strncpy(c, a, na);
|
||||
strncat(c, b, nb);
|
||||
c[nc-1] = '\0';
|
||||
return c;
|
||||
strncat(str, filename, sl);
|
||||
return str;
|
||||
}
|
||||
|
||||
int64_t round_div(int64_t a, int64_t b)
|
||||
|
|
21
src/util.h
21
src/util.h
|
@ -9,18 +9,25 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* \brief strndup with concatenation
|
||||
* \details This function concatenate string a and string b together, and put
|
||||
* the result in a new string.
|
||||
* \param[in] a the first string
|
||||
* \param[in] b the second string
|
||||
* \param[in] n the maximum length of the output string
|
||||
* \brief the maximum length of a path and a URL.
|
||||
* \details This corresponds the maximum path length under Ext4.
|
||||
*/
|
||||
char *strndupcat(const char *a, const char *b, int n);
|
||||
#define MAX_PATH_LEN 4096
|
||||
|
||||
/** \brief the maximum length of a filename. */
|
||||
#define MAX_FILENAME_LEN 255
|
||||
|
||||
/**
|
||||
* \brief append a path
|
||||
* \details This function appends a path with the next level, while taking the
|
||||
* trailing slash of the upper level into account.
|
||||
*/
|
||||
char *path_append(const char *path, const char *filename);
|
||||
|
||||
/**
|
||||
* \brief division, but rounded to the nearest integer rather than truncating
|
||||
*/
|
||||
int64_t round_div(int64_t a, int64_t b);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue