Update ODS2 VHD library with DOS port

Only reason they're separate is because ODS2 uses DOS line endings.
This commit is contained in:
Timothe Litt
2016-03-25 13:01:59 -04:00
parent b00e213506
commit e94ba41122
4 changed files with 203 additions and 146 deletions

View File

@@ -45,7 +45,7 @@
#include <stdlib.h>
#include <inttypes.h>
#ifdef _WIN32
#include <Windows.h>
#include <windows.h>
#include <io.h>
#define strdup _strdup
#define open _open
@@ -157,6 +157,7 @@ static void vhd_log_error( const char *func, const char *fmt, ... )
}
#ifdef _WIN32
LIBVHD_API
char *dirname( char *path ) {
static char buf[MAX_PATH + 1];
char *p, *d;
@@ -193,6 +194,7 @@ char *dirname( char *path ) {
*p = '\0';
return buf;
}
LIBVHD_API
char *basename( char *path ) {
static char buf[MAX_PATH + 1];
char *p, *d;
@@ -580,6 +582,7 @@ static size_t iconv( iconv_t cd,
#define BIT_MASK 0x80
#ifdef ENABLE_FAILURE_TESTING
LIBVHD_API
const char* ENV_VAR_FAIL[NUM_FAIL_TESTS] = {
"VHD_UTIL_TEST_FAIL_REPARENT_BEGIN",
"VHD_UTIL_TEST_FAIL_REPARENT_LOCATOR",
@@ -589,6 +592,7 @@ const char* ENV_VAR_FAIL[NUM_FAIL_TESTS] = {
"VHD_UTIL_TEST_FAIL_RESIZE_METADATA_MOVED",
"VHD_UTIL_TEST_FAIL_RESIZE_END"
};
LIBVHD_API
int TEST_FAIL[NUM_FAIL_TESTS];
#endif /* ENABLE_FAILURE_TESTING */
@@ -1261,7 +1265,7 @@ vhd_time_to_string(uint32_t timestamp, char *target)
t2 = t1 + (time_t)timestamp;
#ifdef _WIN32
t3 = (__time32_t)t2;
_ctime32_s( target, 27, &t3 );
_ctime32_s( target, 26, &t3 );
#else
ctime_r(&t2, target);
#endif
@@ -1835,7 +1839,7 @@ vhd_test_file_fixed(const char *file, int *is_block)
int
vhd_find_parent(vhd_context_t *ctx, const char *parent, char **_location)
{
int err;
int err, isabs = 0, isrd = 0;
char *location, *cpath, *cdir, *path;
err = 0;
@@ -1847,58 +1851,65 @@ vhd_find_parent(vhd_context_t *ctx, const char *parent, char **_location)
if (!parent)
return -EINVAL;
if (parent[0] == '/') {
int ok;
#ifdef _WIN32
int fd;
if( (fd = _open( parent, _O_RDONLY | _O_BINARY )) != -1 ) {
_close( fd );
ok = 1;
} else
ok = 0;
#else
ok = !access( parent, R_OK );
#endif
if( ok) {
path = strdup( parent );
if( !path )
return -ENOMEM;
*_location = path;
return 0;
if( parent[0] == '/' )
isabs = 1;
else {
const char *p;
for( p = parent; *p && *p != '/' && *p != ':'; p++ )
;
isabs = ( *p == ':' );
}
if( isabs ) {
if( (isrd = _open( parent, _O_RDONLY | _O_BINARY )) == -1 )
goto errout;
else {
_close( isrd );
isrd = 1;
}
}
#else
if (parent[0] == '/') {
isabs = 1;
isrd = !access( parent, R_OK );
}
#endif
if( isabs ) {
if( isrd ) {
path = strdup( parent );
if( !path )
return -ENOMEM;
*_location = path;
return 0;
}
goto errout;
}
/* check parent path relative to child's directory */
cpath = realpath(ctx->file, NULL);
if (!cpath) {
err = -errno;
goto out;
}
if (!cpath)
goto errout;
#ifdef _WIN32
cdir = dirname( cpath + 1 );
cdir = dirname( cpath + 1 );
#else
cdir = dirname( cpath );
cdir = dirname( cpath );
#endif
if (asprintf(&location, "%s/%s", cdir, parent) == -1) {
err = -errno;
location = NULL;
goto out;
goto errout;
}
{
int ok;
#ifdef _WIN32
int fd;
if( (fd = _open( location, _O_RDONLY | _O_BINARY )) != -1 ) {
_close( fd );
ok = 1;
} else
ok = 0;
if( (isrd = _open( location, _O_RDONLY | _O_BINARY )) == -1 )
isrd = 0;
else {
_close( isrd );
isrd = 1;
}
#else
ok = !access( location, R_OK );
isrd = !access( location, R_OK );
#endif
if( ok ) {
if( isrd ) {
path = realpath( location, NULL );
if( path ) {
#ifdef _WIN32
@@ -1912,16 +1923,15 @@ vhd_find_parent(vhd_context_t *ctx, const char *parent, char **_location)
return 0;
}
}
}
err = -errno;
out:
errout:
err = -errno;
free(location);
free(cpath);
return err;
}
static int
static int
vhd_macx_encode_location(char *name, char **out, size_t *outlen)
{
iconv_t cd;
@@ -1938,7 +1948,7 @@ vhd_macx_encode_location(char *name, char **out, size_t *outlen)
len = strlen(name) + strlen("file://");
ibl = len;
obl = len;
obl = len * 2;
urip = uri = malloc(ibl + 1);
uri_utf8 = uri_utf8p = malloc(obl);
@@ -1959,11 +1969,11 @@ vhd_macx_encode_location(char *name, char **out, size_t *outlen)
(char **)
#endif
&urip, &ibl, &uri_utf8p, &obl) == (size_t)-1 ||
ibl || obl) {
ibl) {
err = (errno ? -errno : -EIO);
goto out;
}
len = (size_t)(uri_utf8p - uri_utf8);
ret = malloc(len);
if (!ret) {
err = -ENOMEM;
@@ -2030,7 +2040,7 @@ vhd_w2u_encode_location(char *name, char **out, size_t *outlen)
len = strlen(uri);
ibl = len;
obl = len * 2;
obl = len * 4;
urip = uri;
uri_utf16 = uri_utf16p = malloc(obl);
@@ -2054,12 +2064,12 @@ vhd_w2u_encode_location(char *name, char **out, size_t *outlen)
(char **)
#endif
&urip, &ibl, &uri_utf16p, &obl) == (size_t)-1 ||
ibl || obl) {
ibl) {
err = (errno ? -errno : -EIO);
goto out;
}
len = len * 2;
len = (size_t)(uri_utf16p - uri_utf16);
ret = malloc(len);
if (!ret) {
err = -ENOMEM;
@@ -2123,15 +2133,17 @@ vhd_w2u_decode_location(const char *in, char *out, int len, char *utf_type)
ibl = obl = len;
cd = iconv_open("ASCII", utf_type);
if (cd == (iconv_t)-1)
if (cd == (iconv_t)-1)
return NULL;
if (iconv(cd,
#ifdef __linux__
(char **)
#endif
&in, &ibl, &out, &obl) == (size_t)-1 || ibl)
return NULL;
&in, &ibl, &out, &obl) == (size_t)-1 || ibl) {
iconv_close(cd);
return NULL;
}
iconv_close(cd);
*out = '\0';
@@ -2145,14 +2157,13 @@ vhd_w2u_decode_location(const char *in, char *out, int len, char *utf_type)
if (strstr(name, "C:") == name || strstr(name, "c:") == name)
name += strlen("c:");
return strdup(name);
}
int
vhd_header_decode_parent(vhd_context_t *ctx, vhd_header_t *header, char **buf)
{
char *code, out[512];
char *code, out[512+1];
if (vhd_creator_tapdisk(ctx) &&
ctx->footer.crtr_ver == VHD_VERSION(0, 1))
@@ -3289,7 +3300,7 @@ vhd_initialize_header(vhd_context_t *ctx, const char *parent_path,
err = vhd_open(&parent, parent_path, VHD_OPEN_RDONLY);
if (err)
return err;
ctx->header.prt_ts = vhd_time(stats.st_mtime);
blk_uuid_copy(&ctx->header.prt_uuid, &parent.footer.uuid);
if (!size)
@@ -3347,7 +3358,7 @@ vhd_write_parent_locators(vhd_context_t *ctx, const char *parent)
}
int
int
vhd_change_parent(vhd_context_t *child, char *parent_path, int flags)
{
int i, err;
char *ppath;
@@ -3360,7 +3371,9 @@ vhd_change_parent(vhd_context_t *child, char *parent_path, int raw)
parent_path, child->file, errno));
return -errno;
}
}
#ifdef _WIN32
ppath++;
#endif
err = stat(ppath, &stats);
if (err == -1) {
err = -errno;
@@ -3380,7 +3393,7 @@ vhd_change_parent(vhd_context_t *child, char *parent_path, int raw)
}
#endif
if (flags & 1) {
blk_uuid_clear(&child->header.prt_uuid);
} else {
err = vhd_open(&parent, ppath, VHD_OPEN_RDONLY);
@@ -3389,7 +3402,18 @@ vhd_change_parent(vhd_context_t *child, char *parent_path, int raw)
ppath, child->file, err));
goto out;
}
}
/* Extension */
if( flags & 2 ) {
if( blk_uuid_compare(&child->header.prt_uuid,
&parent.footer.uuid) != 0 ) {
VHDLOG((FN,"new parent %s for %s: parent UUID doesn't match child\n",
ppath, child->file));
vhd_close(&parent);
err = -EINVAL;
goto out;
}
} else
blk_uuid_copy(&child->header.prt_uuid, &parent.footer.uuid);
vhd_close(&parent);
}
@@ -3430,7 +3454,11 @@ vhd_change_parent(vhd_context_t *child, char *parent_path, int raw)
err = 0;
out:
#ifdef _WIN32
free(ppath -1);
#else
free(ppath);
#endif
return err;
}

View File

@@ -59,6 +59,16 @@
#define O_LARGEFILE 0
#endif
#if defined(_WIN32) && defined(LIBVHD_DLL)
#ifdef LIBVHD_EXPORTS
#define LIBVHD_API __declspec(dllexport)
#else
#define LIBVHD_API __declspec(dllimport)
#endif
#else
#define LIBVHD_API
#endif
#if BYTE_ORDER == LITTLE_ENDIAN
#if defined(__linux__) || defined(_WIN32)
#define BE16_IN(foo) (*(foo)) = bswap_16(*(foo))
@@ -109,7 +119,9 @@
#define vhd_flag_test(word, flag) ((word) & (flag))
#define ENABLE_FAILURE_TESTING
#ifndef _WIN32x
#define ENABLE_FAILURE_TESTING 1
#endif
#define FAIL_REPARENT_BEGIN 0
#define FAIL_REPARENT_LOCATOR 1
#define FAIL_REPARENT_END 2
@@ -123,9 +135,15 @@
#define TEST_FAIL_AT(point) \
if (TEST_FAIL[point]) { \
printf("Failing at %s\n", ENV_VAR_FAIL[point]); exit(EINVAL); }
#ifdef _WIN32
#define TEST_FAIL_EXTERN_VARS \
extern const char* ENV_VAR_FAIL[]; \
extern int TEST_FAIL[];
LIBVHD_API extern const char* ENV_VAR_FAIL[]; \
LIBVHD_API extern int TEST_FAIL[];
#else
#define TEST_FAIL_EXTERN_VARS \
extern const char* ENV_VAR_FAIL[]; \
extern int TEST_FAIL[];
#endif
#else
#define TEST_FAIL_AT(point)
#define TEST_FAIL_EXTERN_VARS
@@ -238,108 +256,108 @@ vhd_parent_raw(vhd_context_t *ctx)
return blk_uuid_is_nil(&ctx->header.prt_uuid);
}
void libvhd_set_log_level(int);
LIBVHD_API void libvhd_set_log_level(int);
int vhd_test_file_fixed(const char *, int *);
LIBVHD_API int vhd_test_file_fixed(const char *, int *);
uint32_t vhd_time(time_t time);
size_t vhd_time_to_string(uint32_t timestamp, char *target);
uint32_t vhd_chs(uint64_t size);
LIBVHD_API uint32_t vhd_time(time_t time);
LIBVHD_API size_t vhd_time_to_string(uint32_t timestamp, char *target);
LIBVHD_API uint32_t vhd_chs(uint64_t size);
uint32_t vhd_checksum_footer(vhd_footer_t *);
uint32_t vhd_checksum_header(vhd_header_t *);
uint32_t vhd_checksum_batmap(vhd_batmap_t *);
LIBVHD_API uint32_t vhd_checksum_footer(vhd_footer_t *);
LIBVHD_API uint32_t vhd_checksum_header(vhd_header_t *);
LIBVHD_API uint32_t vhd_checksum_batmap(vhd_batmap_t *);
void vhd_footer_in(vhd_footer_t *);
void vhd_footer_out(vhd_footer_t *);
void vhd_header_in(vhd_header_t *);
void vhd_header_out(vhd_header_t *);
void vhd_bat_in(vhd_bat_t *);
void vhd_bat_out(vhd_bat_t *);
void vhd_batmap_header_in(vhd_batmap_t *);
void vhd_batmap_header_out(vhd_batmap_t *);
LIBVHD_API void vhd_footer_in(vhd_footer_t *);
LIBVHD_API void vhd_footer_out(vhd_footer_t *);
LIBVHD_API void vhd_header_in(vhd_header_t *);
LIBVHD_API void vhd_header_out(vhd_header_t *);
LIBVHD_API void vhd_bat_in(vhd_bat_t *);
LIBVHD_API void vhd_bat_out(vhd_bat_t *);
LIBVHD_API void vhd_batmap_header_in(vhd_batmap_t *);
LIBVHD_API void vhd_batmap_header_out(vhd_batmap_t *);
int vhd_validate_footer(vhd_footer_t *footer);
int vhd_validate_header(vhd_header_t *header);
int vhd_validate_batmap_header(vhd_batmap_t *batmap);
int vhd_validate_batmap(vhd_batmap_t *batmap);
int vhd_validate_platform_code(uint32_t code);
LIBVHD_API int vhd_validate_footer(vhd_footer_t *footer);
LIBVHD_API int vhd_validate_header(vhd_header_t *header);
LIBVHD_API int vhd_validate_batmap_header(vhd_batmap_t *batmap);
LIBVHD_API int vhd_validate_batmap(vhd_batmap_t *batmap);
LIBVHD_API int vhd_validate_platform_code(uint32_t code);
int vhd_open(vhd_context_t *, const char *file, int flags);
void vhd_close(vhd_context_t *);
int vhd_create(const char *name, uint64_t bytes, int type, vhd_flag_creat_t);
LIBVHD_API int vhd_open(vhd_context_t *, const char *file, int flags);
LIBVHD_API void vhd_close(vhd_context_t *);
LIBVHD_API int vhd_create(const char *name, uint64_t bytes, int type, vhd_flag_creat_t);
/* vhd_snapshot: the bytes parameter is optional and can be 0 if the snapshot
* is to have the same size as the (first non-empty) parent */
int vhd_snapshot(const char *snapshot, uint64_t bytes, const char *parent,
LIBVHD_API int vhd_snapshot(const char *snapshot, uint64_t bytes, const char *parent,
vhd_flag_creat_t);
int vhd_hidden(vhd_context_t *, int *);
int vhd_chain_depth(vhd_context_t *, int *);
LIBVHD_API int vhd_hidden(vhd_context_t *, int *);
LIBVHD_API int vhd_chain_depth(vhd_context_t *, int *);
off_t vhd_position(vhd_context_t *);
int vhd_seek(vhd_context_t *, off_t, int);
int vhd_read(vhd_context_t *, void *, size_t);
int vhd_write(vhd_context_t *, void *, size_t);
LIBVHD_API off_t vhd_position(vhd_context_t *);
LIBVHD_API int vhd_seek(vhd_context_t *, off_t, int);
LIBVHD_API int vhd_read(vhd_context_t *, void *, size_t);
LIBVHD_API int vhd_write(vhd_context_t *, void *, size_t);
int vhd_offset(vhd_context_t *, uint32_t, uint32_t *);
LIBVHD_API int vhd_offset(vhd_context_t *, uint32_t, uint32_t *);
int vhd_end_of_headers(vhd_context_t *ctx, off_t *off);
int vhd_end_of_data(vhd_context_t *ctx, off_t *off);
int vhd_batmap_header_offset(vhd_context_t *ctx, off_t *off);
LIBVHD_API int vhd_end_of_headers(vhd_context_t *ctx, off_t *off);
LIBVHD_API int vhd_end_of_data(vhd_context_t *ctx, off_t *off);
LIBVHD_API int vhd_batmap_header_offset(vhd_context_t *ctx, off_t *off);
int vhd_get_header(vhd_context_t *);
int vhd_get_footer(vhd_context_t *);
int vhd_get_bat(vhd_context_t *);
int vhd_get_batmap(vhd_context_t *);
LIBVHD_API int vhd_get_header(vhd_context_t *);
LIBVHD_API int vhd_get_footer(vhd_context_t *);
LIBVHD_API int vhd_get_bat(vhd_context_t *);
LIBVHD_API int vhd_get_batmap(vhd_context_t *);
void vhd_put_header(vhd_context_t *);
void vhd_put_footer(vhd_context_t *);
void vhd_put_bat(vhd_context_t *);
void vhd_put_batmap(vhd_context_t *);
LIBVHD_API void vhd_put_header(vhd_context_t *);
LIBVHD_API void vhd_put_footer(vhd_context_t *);
LIBVHD_API void vhd_put_bat(vhd_context_t *);
LIBVHD_API void vhd_put_batmap(vhd_context_t *);
int vhd_has_batmap(vhd_context_t *);
int vhd_batmap_test(vhd_context_t *, vhd_batmap_t *, uint32_t);
void vhd_batmap_set(vhd_context_t *, vhd_batmap_t *, uint32_t);
void vhd_batmap_clear(vhd_context_t *, vhd_batmap_t *, uint32_t);
LIBVHD_API int vhd_has_batmap(vhd_context_t *);
LIBVHD_API int vhd_batmap_test(vhd_context_t *, vhd_batmap_t *, uint32_t);
LIBVHD_API void vhd_batmap_set(vhd_context_t *, vhd_batmap_t *, uint32_t);
LIBVHD_API void vhd_batmap_clear(vhd_context_t *, vhd_batmap_t *, uint32_t);
int vhd_get_phys_size(vhd_context_t *, off_t *);
int vhd_set_phys_size(vhd_context_t *, off_t);
LIBVHD_API int vhd_get_phys_size(vhd_context_t *, off_t *);
LIBVHD_API int vhd_set_phys_size(vhd_context_t *, off_t);
int vhd_bitmap_test(vhd_context_t *, char *, uint32_t);
void vhd_bitmap_set(vhd_context_t *, char *, uint32_t);
void vhd_bitmap_clear(vhd_context_t *, char *, uint32_t);
LIBVHD_API int vhd_bitmap_test(vhd_context_t *, char *, uint32_t);
LIBVHD_API void vhd_bitmap_set(vhd_context_t *, char *, uint32_t);
LIBVHD_API void vhd_bitmap_clear(vhd_context_t *, char *, uint32_t);
int vhd_parent_locator_count(vhd_context_t *);
int vhd_parent_locator_get(vhd_context_t *, char **);
int vhd_parent_locator_read(vhd_context_t *, vhd_parent_locator_t *, char **);
int vhd_find_parent(vhd_context_t *, const char *, char **);
int vhd_parent_locator_write_at(vhd_context_t *, const char *,
LIBVHD_API int vhd_parent_locator_count(vhd_context_t *);
LIBVHD_API int vhd_parent_locator_get(vhd_context_t *, char **);
LIBVHD_API int vhd_parent_locator_read(vhd_context_t *, vhd_parent_locator_t *, char **);
LIBVHD_API int vhd_find_parent(vhd_context_t *, const char *, char **);
LIBVHD_API int vhd_parent_locator_write_at(vhd_context_t *, const char *,
off_t, uint32_t, size_t,
vhd_parent_locator_t *);
int vhd_header_decode_parent(vhd_context_t *, vhd_header_t *, char **);
int vhd_change_parent(vhd_context_t *, char *parent_path, int raw);
LIBVHD_API int vhd_header_decode_parent(vhd_context_t *, vhd_header_t *, char **);
LIBVHD_API int vhd_change_parent(vhd_context_t *, char *parent_path, int raw);
int vhd_read_footer(vhd_context_t *, vhd_footer_t *);
int vhd_read_footer_at(vhd_context_t *, vhd_footer_t *, off_t);
int vhd_read_footer_strict(vhd_context_t *, vhd_footer_t *);
int vhd_read_header(vhd_context_t *, vhd_header_t *);
int vhd_read_header_at(vhd_context_t *, vhd_header_t *, off_t);
int vhd_read_bat(vhd_context_t *, vhd_bat_t *);
int vhd_read_batmap(vhd_context_t *, vhd_batmap_t *);
int vhd_read_bitmap(vhd_context_t *, uint32_t block, char **bufp);
int vhd_read_block(vhd_context_t *, uint32_t block, char **bufp);
LIBVHD_API int vhd_read_footer(vhd_context_t *, vhd_footer_t *);
LIBVHD_API int vhd_read_footer_at(vhd_context_t *, vhd_footer_t *, off_t);
LIBVHD_API int vhd_read_footer_strict(vhd_context_t *, vhd_footer_t *);
LIBVHD_API int vhd_read_header(vhd_context_t *, vhd_header_t *);
LIBVHD_API int vhd_read_header_at(vhd_context_t *, vhd_header_t *, off_t);
LIBVHD_API int vhd_read_bat(vhd_context_t *, vhd_bat_t *);
LIBVHD_API int vhd_read_batmap(vhd_context_t *, vhd_batmap_t *);
LIBVHD_API int vhd_read_bitmap(vhd_context_t *, uint32_t block, char **bufp);
LIBVHD_API int vhd_read_block(vhd_context_t *, uint32_t block, char **bufp);
int vhd_write_footer(vhd_context_t *, vhd_footer_t *);
int vhd_write_footer_at(vhd_context_t *, vhd_footer_t *, off_t);
int vhd_write_header(vhd_context_t *, vhd_header_t *);
int vhd_write_header_at(vhd_context_t *, vhd_header_t *, off_t);
int vhd_write_bat(vhd_context_t *, vhd_bat_t *);
int vhd_write_batmap(vhd_context_t *, vhd_batmap_t *);
int vhd_write_bitmap(vhd_context_t *, uint32_t block, char *bitmap);
int vhd_write_block(vhd_context_t *, uint32_t block, char *data);
LIBVHD_API int vhd_write_footer(vhd_context_t *, vhd_footer_t *);
LIBVHD_API int vhd_write_footer_at(vhd_context_t *, vhd_footer_t *, off_t);
LIBVHD_API int vhd_write_header(vhd_context_t *, vhd_header_t *);
LIBVHD_API int vhd_write_header_at(vhd_context_t *, vhd_header_t *, off_t);
LIBVHD_API int vhd_write_bat(vhd_context_t *, vhd_bat_t *);
LIBVHD_API int vhd_write_batmap(vhd_context_t *, vhd_batmap_t *);
LIBVHD_API int vhd_write_bitmap(vhd_context_t *, uint32_t block, char *bitmap);
LIBVHD_API int vhd_write_block(vhd_context_t *, uint32_t block, char *data);
int vhd_io_read(vhd_context_t *, char *, uint64_t, uint32_t);
int vhd_io_write(vhd_context_t *, char *, uint64_t, uint32_t);
LIBVHD_API int vhd_io_read(vhd_context_t *, char *, uint64_t, uint32_t);
LIBVHD_API int vhd_io_write(vhd_context_t *, char *, uint64_t, uint32_t);
#endif

View File

@@ -79,7 +79,7 @@ do { \
} while (0)
#ifdef _WIN32
char *realpath( const char *path, char *resolved ) {
LIBVHD_API char *realpath( const char *path, char *resolved ) {
char *p;
DWORD len;
@@ -122,7 +122,7 @@ char *realpath( const char *path, char *resolved ) {
}
return resolved;
}
int asprintf( char **result, const char *fmt, ... ) {
LIBVHD_API int asprintf( char **result, const char *fmt, ... ) {
int len;
va_list ap;
char *np;
@@ -314,6 +314,7 @@ node_offset(char *from, int offset)
* return a relative path from @from to @to
* result should be freed
*/
LIBVHD_API
char *
relative_path_to(char *from, char *to, int *err)
{

View File

@@ -35,15 +35,25 @@
#define MAX_NAME_LEN 1000
#if defined(_WIN32) && defined(LIBVHD_DLL)
#ifdef LIBVHD_EXPORTS
#define LIBVHD_API __declspec(dllexport)
#else
#define LIBVHD_API __declspec(dllimport)
#endif
#else
#define LIBVHD_API
#endif
/*
* returns a relative path from @src to @dest
* result should be freed
*/
char *relative_path_to(char *src, char *dest, int *err);
LIBVHD_API char *relative_path_to(char *src, char *dest, int *err);
#ifdef _WIN32
char *realpath( const char *path, char *resolved );
int asprintf( char **result, const char *fmt, ... );
LIBVHD_API char *realpath( const char *path, char *resolved );
LIBVHD_API int asprintf( char **result, const char *fmt, ... );
#endif
#endif