2017-10-05 23:32:57 -07:00
|
|
|
/* mz_os_posix.c -- System functions for posix
|
2021-01-23 16:18:11 -08:00
|
|
|
part of the minizip-ng project
|
2017-10-05 23:32:57 -07:00
|
|
|
|
2023-02-16 13:14:21 -08:00
|
|
|
Copyright (C) Nathan Moinvaziri
|
2021-01-23 16:18:11 -08:00
|
|
|
https://github.com/zlib-ng/minizip-ng
|
2017-10-05 23:32:57 -07:00
|
|
|
|
|
|
|
|
This program is distributed under the terms of the same license as zlib.
|
|
|
|
|
See the accompanying LICENSE file for the full text of the license.
|
|
|
|
|
*/
|
|
|
|
|
|
2018-11-20 16:56:21 -08:00
|
|
|
#include "mz.h"
|
2026-04-20 17:26:22 -07:00
|
|
|
#include "mz_config.h"
|
2018-11-20 16:56:21 -08:00
|
|
|
#include "mz_strm.h"
|
|
|
|
|
#include "mz_os.h"
|
|
|
|
|
|
2018-11-21 15:05:58 -08:00
|
|
|
#include <stdio.h> /* rename */
|
2017-10-05 23:32:57 -07:00
|
|
|
#include <errno.h>
|
2020-04-07 19:05:41 -07:00
|
|
|
#if defined(HAVE_ICONV)
|
2024-11-01 16:30:39 -07:00
|
|
|
# include <iconv.h>
|
2020-04-07 19:05:41 -07:00
|
|
|
#endif
|
2026-07-04 10:30:29 +02:00
|
|
|
#if defined(HAVE_ICU)
|
|
|
|
|
# include <unicode/ucnv.h>
|
|
|
|
|
#endif
|
2023-03-31 18:18:31 -07:00
|
|
|
#include <string.h>
|
2017-10-05 23:32:57 -07:00
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
2020-11-18 11:21:17 +00:00
|
|
|
#ifndef _WIN32
|
2018-10-25 21:28:26 -07:00
|
|
|
# include <utime.h>
|
|
|
|
|
# include <unistd.h>
|
|
|
|
|
#endif
|
|
|
|
|
#if defined(__APPLE__)
|
|
|
|
|
# include <mach/clock.h>
|
|
|
|
|
# include <mach/mach.h>
|
2018-09-18 12:06:54 +02:00
|
|
|
#endif
|
|
|
|
|
|
2021-01-10 11:22:05 -08:00
|
|
|
#if defined(HAVE_GETRANDOM)
|
|
|
|
|
# include <sys/random.h>
|
|
|
|
|
#endif
|
|
|
|
|
#if defined(HAVE_LIBBSD)
|
2022-08-11 20:57:32 -07:00
|
|
|
# include <stdlib.h> /* arc4random_buf */
|
2021-01-10 11:22:05 -08:00
|
|
|
#endif
|
|
|
|
|
|
2025-04-14 00:00:07 +02:00
|
|
|
#ifndef MZ_PRESERVE_NATIVE_STRUCTURE
|
|
|
|
|
# define MZ_PRESERVE_NATIVE_STRUCTURE 1
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-10-05 23:32:57 -07:00
|
|
|
/***************************************************************************/
|
|
|
|
|
|
2020-04-07 19:05:41 -07:00
|
|
|
#if defined(HAVE_ICONV)
|
2023-06-08 10:01:07 +02:00
|
|
|
char *mz_os_utf8_string_create(const char *string, int32_t encoding) {
|
2018-10-30 15:31:49 -07:00
|
|
|
iconv_t cd;
|
2025-06-16 14:19:12 -04:00
|
|
|
/// up to CP2147483647
|
|
|
|
|
char string_encoding[13];
|
2018-10-30 15:31:49 -07:00
|
|
|
const char *from_encoding = NULL;
|
2019-05-01 09:10:29 -07:00
|
|
|
size_t result = 0;
|
2018-10-30 15:31:49 -07:00
|
|
|
size_t string_length = 0;
|
|
|
|
|
size_t string_utf8_size = 0;
|
2023-06-08 10:01:07 +02:00
|
|
|
char *string_utf8 = NULL;
|
|
|
|
|
char *string_utf8_ptr = NULL;
|
2018-10-30 15:31:49 -07:00
|
|
|
|
2025-05-01 17:11:50 +02:00
|
|
|
if (!string || encoding <= 0)
|
2018-10-30 15:31:49 -07:00
|
|
|
return NULL;
|
|
|
|
|
|
2025-05-01 17:11:50 +02:00
|
|
|
if (encoding == MZ_ENCODING_UTF8)
|
2018-10-30 15:31:49 -07:00
|
|
|
from_encoding = "UTF-8";
|
2025-05-01 17:11:50 +02:00
|
|
|
else {
|
|
|
|
|
snprintf(string_encoding, sizeof(string_encoding), "CP%03" PRId32, encoding);
|
|
|
|
|
from_encoding = string_encoding;
|
|
|
|
|
}
|
2018-10-30 15:31:49 -07:00
|
|
|
|
|
|
|
|
cd = iconv_open("UTF-8", from_encoding);
|
|
|
|
|
if (cd == (iconv_t)-1)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
string_length = strlen(string);
|
|
|
|
|
string_utf8_size = string_length * 2;
|
2023-06-08 10:01:07 +02:00
|
|
|
string_utf8 = (char *)calloc((int32_t)(string_utf8_size + 1), sizeof(char));
|
2018-10-30 15:31:49 -07:00
|
|
|
string_utf8_ptr = string_utf8;
|
|
|
|
|
|
2020-06-14 15:19:14 -07:00
|
|
|
if (string_utf8) {
|
2024-11-01 16:30:39 -07:00
|
|
|
result = iconv(cd, (char **)&string, &string_length, (char **)&string_utf8_ptr, &string_utf8_size);
|
2018-10-30 15:31:49 -07:00
|
|
|
}
|
|
|
|
|
|
2019-05-01 09:10:29 -07:00
|
|
|
iconv_close(cd);
|
|
|
|
|
|
2020-06-14 15:19:14 -07:00
|
|
|
if (result == (size_t)-1) {
|
2023-02-24 14:23:04 -08:00
|
|
|
free(string_utf8);
|
2018-10-30 15:31:49 -07:00
|
|
|
string_utf8 = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return string_utf8;
|
|
|
|
|
}
|
2026-07-04 10:30:29 +02:00
|
|
|
#elif defined(HAVE_ICU)
|
|
|
|
|
char *mz_os_utf8_string_create(const char *string, int32_t encoding) {
|
|
|
|
|
char string_encoding[16];
|
|
|
|
|
const char *from_encoding = NULL;
|
|
|
|
|
int32_t string_length = 0;
|
|
|
|
|
int32_t string_utf8_size = 0;
|
|
|
|
|
char *string_utf8 = NULL;
|
|
|
|
|
int32_t result = 0;
|
|
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
|
|
|
|
|
|
|
|
if (!string || encoding <= 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (encoding == MZ_ENCODING_UTF8)
|
|
|
|
|
from_encoding = "UTF-8";
|
|
|
|
|
else if (encoding == MZ_ENCODING_CODEPAGE_437)
|
|
|
|
|
from_encoding = "ibm-437";
|
|
|
|
|
else if (encoding == MZ_ENCODING_CODEPAGE_932)
|
|
|
|
|
from_encoding = "windows-932-2000";
|
|
|
|
|
else if (encoding == MZ_ENCODING_CODEPAGE_936)
|
|
|
|
|
from_encoding = "windows-936-2000";
|
|
|
|
|
else if (encoding == MZ_ENCODING_CODEPAGE_950)
|
|
|
|
|
from_encoding = "windows-950-2000";
|
|
|
|
|
else {
|
|
|
|
|
snprintf(string_encoding, sizeof(string_encoding), "windows-%" PRId32 "-2000", encoding);
|
|
|
|
|
from_encoding = string_encoding;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string_length = (int32_t)strlen(string);
|
|
|
|
|
string_utf8_size = string_length * 4 + 1;
|
|
|
|
|
string_utf8 = (char *)calloc(string_utf8_size, sizeof(char));
|
|
|
|
|
|
|
|
|
|
if (!string_utf8)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
result = ucnv_convert("UTF-8", from_encoding, string_utf8, string_utf8_size, string, string_length, &status);
|
|
|
|
|
|
|
|
|
|
if (U_FAILURE(status) || result < 0) {
|
|
|
|
|
free(string_utf8);
|
|
|
|
|
string_utf8 = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return string_utf8;
|
|
|
|
|
}
|
2020-04-07 19:05:41 -07:00
|
|
|
#else
|
2023-06-08 10:01:07 +02:00
|
|
|
char *mz_os_utf8_string_create(const char *string, int32_t encoding) {
|
|
|
|
|
return strdup(string);
|
2020-04-07 19:05:41 -07:00
|
|
|
}
|
|
|
|
|
#endif
|
2018-10-30 15:31:49 -07:00
|
|
|
|
2023-06-08 10:01:07 +02:00
|
|
|
void mz_os_utf8_string_delete(char **string) {
|
2023-02-19 11:17:54 -08:00
|
|
|
if (string) {
|
2023-02-24 14:23:04 -08:00
|
|
|
free(*string);
|
2018-10-30 15:31:49 -07:00
|
|
|
*string = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
2022-10-02 01:39:17 +01:00
|
|
|
#if defined(HAVE_GETRANDOM)
|
|
|
|
|
int32_t mz_os_rand(uint8_t *buf, int32_t size) {
|
|
|
|
|
int32_t left = size;
|
|
|
|
|
int32_t written = 0;
|
|
|
|
|
|
|
|
|
|
while (left > 0) {
|
|
|
|
|
written = getrandom(buf, left, 0);
|
|
|
|
|
if (written < 0)
|
|
|
|
|
return MZ_INTERNAL_ERROR;
|
|
|
|
|
|
|
|
|
|
buf += written;
|
|
|
|
|
left -= written;
|
|
|
|
|
}
|
|
|
|
|
return size - left;
|
|
|
|
|
}
|
|
|
|
|
#elif defined(HAVE_ARC4RANDOM_BUF)
|
2021-01-10 11:22:05 -08:00
|
|
|
int32_t mz_os_rand(uint8_t *buf, int32_t size) {
|
|
|
|
|
if (size < 0)
|
|
|
|
|
return 0;
|
|
|
|
|
arc4random_buf(buf, (uint32_t)size);
|
|
|
|
|
return size;
|
|
|
|
|
}
|
|
|
|
|
#elif defined(HAVE_ARC4RANDOM)
|
|
|
|
|
int32_t mz_os_rand(uint8_t *buf, int32_t size) {
|
|
|
|
|
int32_t left = size;
|
|
|
|
|
for (; left > 2; left -= 3, buf += 3) {
|
|
|
|
|
uint32_t val = arc4random();
|
|
|
|
|
|
|
|
|
|
buf[0] = (val) & 0xFF;
|
|
|
|
|
buf[1] = (val >> 8) & 0xFF;
|
|
|
|
|
buf[2] = (val >> 16) & 0xFF;
|
|
|
|
|
}
|
|
|
|
|
for (; left > 0; left--, buf++) {
|
|
|
|
|
*buf = arc4random() & 0xFF;
|
|
|
|
|
}
|
|
|
|
|
return size - left;
|
|
|
|
|
}
|
|
|
|
|
#else
|
2020-06-14 15:19:14 -07:00
|
|
|
int32_t mz_os_rand(uint8_t *buf, int32_t size) {
|
2018-07-22 12:15:04 -07:00
|
|
|
static unsigned calls = 0;
|
|
|
|
|
int32_t i = 0;
|
|
|
|
|
|
2018-11-20 16:56:21 -08:00
|
|
|
/* Ensure different random header each time */
|
2020-06-14 15:19:14 -07:00
|
|
|
if (++calls == 1) {
|
2024-11-01 16:30:39 -07:00
|
|
|
# define PI_SEED 3141592654UL
|
2018-07-22 12:15:04 -07:00
|
|
|
srand((unsigned)(time(NULL) ^ PI_SEED));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (i < size)
|
|
|
|
|
buf[i++] = (rand() >> 7) & 0xff;
|
|
|
|
|
|
|
|
|
|
return size;
|
|
|
|
|
}
|
2021-01-10 11:22:05 -08:00
|
|
|
#endif
|
2017-10-05 23:32:57 -07:00
|
|
|
|
2020-06-14 15:19:14 -07:00
|
|
|
int32_t mz_os_rename(const char *source_path, const char *target_path) {
|
2018-07-31 10:06:12 -07:00
|
|
|
if (rename(source_path, target_path) == -1)
|
|
|
|
|
return MZ_EXIST_ERROR;
|
|
|
|
|
|
|
|
|
|
return MZ_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-25 01:01:34 -07:00
|
|
|
int32_t mz_os_path_same_fs(const char *path_a, const char *path_b) {
|
|
|
|
|
struct stat sa, sb;
|
|
|
|
|
if (!path_a || !path_b)
|
|
|
|
|
return MZ_PARAM_ERROR;
|
|
|
|
|
if (stat(path_a, &sa) != 0 || stat(path_b, &sb) != 0)
|
|
|
|
|
return MZ_EXIST_ERROR;
|
|
|
|
|
return (sa.st_dev == sb.st_dev) ? MZ_OK : MZ_EXIST_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-14 15:19:14 -07:00
|
|
|
int32_t mz_os_unlink(const char *path) {
|
2018-07-31 10:06:12 -07:00
|
|
|
if (unlink(path) == -1)
|
|
|
|
|
return MZ_EXIST_ERROR;
|
|
|
|
|
|
|
|
|
|
return MZ_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-14 15:19:14 -07:00
|
|
|
int32_t mz_os_file_exists(const char *path) {
|
2018-11-24 17:08:11 -08:00
|
|
|
struct stat path_stat;
|
2017-10-23 18:27:18 -07:00
|
|
|
|
2018-11-24 17:08:11 -08:00
|
|
|
memset(&path_stat, 0, sizeof(path_stat));
|
|
|
|
|
if (stat(path, &path_stat) == 0)
|
2017-10-23 18:32:53 -07:00
|
|
|
return MZ_OK;
|
|
|
|
|
return MZ_EXIST_ERROR;
|
2017-10-23 18:27:18 -07:00
|
|
|
}
|
|
|
|
|
|
2020-06-14 15:19:14 -07:00
|
|
|
int64_t mz_os_get_file_size(const char *path) {
|
2018-11-24 17:08:11 -08:00
|
|
|
struct stat path_stat;
|
2017-10-23 18:27:18 -07:00
|
|
|
|
2018-11-24 17:08:11 -08:00
|
|
|
memset(&path_stat, 0, sizeof(path_stat));
|
2020-06-14 15:19:14 -07:00
|
|
|
if (stat(path, &path_stat) == 0) {
|
2018-11-24 17:08:11 -08:00
|
|
|
/* Stat returns size taken up by directory entry, so return 0 */
|
|
|
|
|
if (S_ISDIR(path_stat.st_mode))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return path_stat.st_size;
|
|
|
|
|
}
|
2017-10-23 18:27:18 -07:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-14 15:19:14 -07:00
|
|
|
int32_t mz_os_get_file_date(const char *path, time_t *modified_date, time_t *accessed_date, time_t *creation_date) {
|
2018-11-24 17:08:11 -08:00
|
|
|
struct stat path_stat;
|
2017-10-22 14:32:37 -07:00
|
|
|
char *name = NULL;
|
2017-10-20 07:59:39 -07:00
|
|
|
int32_t err = MZ_INTERNAL_ERROR;
|
2017-10-05 23:32:57 -07:00
|
|
|
|
2018-11-24 17:08:11 -08:00
|
|
|
memset(&path_stat, 0, sizeof(path_stat));
|
2017-10-05 23:32:57 -07:00
|
|
|
|
2020-06-14 15:19:14 -07:00
|
|
|
if (strcmp(path, "-") != 0) {
|
2018-11-20 16:56:21 -08:00
|
|
|
/* Not all systems allow stat'ing a file with / appended */
|
2023-02-24 14:35:31 -08:00
|
|
|
name = strdup(path);
|
2019-05-02 21:07:39 -07:00
|
|
|
mz_path_remove_slash(name);
|
2017-10-05 23:32:57 -07:00
|
|
|
|
2020-06-14 15:19:14 -07:00
|
|
|
if (stat(name, &path_stat) == 0) {
|
2023-02-19 11:17:54 -08:00
|
|
|
if (modified_date)
|
2018-11-24 17:08:11 -08:00
|
|
|
*modified_date = path_stat.st_mtime;
|
2023-02-19 11:17:54 -08:00
|
|
|
if (accessed_date)
|
2018-11-24 17:08:11 -08:00
|
|
|
*accessed_date = path_stat.st_atime;
|
2018-11-20 16:56:21 -08:00
|
|
|
/* Creation date not supported */
|
2023-02-19 11:17:54 -08:00
|
|
|
if (creation_date)
|
2017-10-22 14:32:37 -07:00
|
|
|
*creation_date = 0;
|
|
|
|
|
|
2017-10-05 23:32:57 -07:00
|
|
|
err = MZ_OK;
|
|
|
|
|
}
|
2017-10-22 14:32:37 -07:00
|
|
|
|
2017-10-05 23:32:57 -07:00
|
|
|
free(name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-14 15:19:14 -07:00
|
|
|
int32_t mz_os_set_file_date(const char *path, time_t modified_date, time_t accessed_date, time_t creation_date) {
|
2017-10-05 23:32:57 -07:00
|
|
|
struct utimbuf ut;
|
|
|
|
|
|
2017-10-22 14:32:37 -07:00
|
|
|
ut.actime = accessed_date;
|
|
|
|
|
ut.modtime = modified_date;
|
2018-11-24 17:08:11 -08:00
|
|
|
|
2018-11-20 16:56:21 -08:00
|
|
|
/* Creation date not supported */
|
2018-11-24 17:08:11 -08:00
|
|
|
MZ_UNUSED(creation_date);
|
2017-10-05 23:32:57 -07:00
|
|
|
|
|
|
|
|
if (utime(path, &ut) != 0)
|
|
|
|
|
return MZ_INTERNAL_ERROR;
|
|
|
|
|
|
|
|
|
|
return MZ_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-14 15:19:14 -07:00
|
|
|
int32_t mz_os_get_file_attribs(const char *path, uint32_t *attributes) {
|
2018-11-24 17:08:11 -08:00
|
|
|
struct stat path_stat;
|
2018-05-01 13:45:08 -07:00
|
|
|
int32_t err = MZ_OK;
|
|
|
|
|
|
2018-11-24 17:08:11 -08:00
|
|
|
memset(&path_stat, 0, sizeof(path_stat));
|
2026-04-26 18:21:36 -07:00
|
|
|
if (stat(path, &path_stat) == -1)
|
2018-05-01 13:45:08 -07:00
|
|
|
err = MZ_INTERNAL_ERROR;
|
2018-11-24 17:08:11 -08:00
|
|
|
*attributes = path_stat.st_mode;
|
2018-05-01 13:45:08 -07:00
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-14 15:19:14 -07:00
|
|
|
int32_t mz_os_set_file_attribs(const char *path, uint32_t attributes) {
|
2018-05-01 13:45:08 -07:00
|
|
|
int32_t err = MZ_OK;
|
|
|
|
|
|
2018-05-09 09:42:31 -07:00
|
|
|
if (chmod(path, (mode_t)attributes) == -1)
|
2018-05-01 13:45:08 -07:00
|
|
|
err = MZ_INTERNAL_ERROR;
|
|
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-14 15:19:14 -07:00
|
|
|
int32_t mz_os_make_dir(const char *path) {
|
2017-10-20 07:59:39 -07:00
|
|
|
int32_t err = 0;
|
2017-10-05 23:32:57 -07:00
|
|
|
|
|
|
|
|
err = mkdir(path, 0755);
|
|
|
|
|
|
|
|
|
|
if (err != 0 && errno != EEXIST)
|
|
|
|
|
return MZ_INTERNAL_ERROR;
|
|
|
|
|
|
|
|
|
|
return MZ_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-01 16:30:39 -07:00
|
|
|
DIR *mz_os_open_dir(const char *path) {
|
2017-10-05 23:32:57 -07:00
|
|
|
return opendir(path);
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-01 16:30:39 -07:00
|
|
|
struct dirent *mz_os_read_dir(DIR *dir) {
|
2023-02-19 11:17:54 -08:00
|
|
|
if (!dir)
|
2017-10-05 23:32:57 -07:00
|
|
|
return NULL;
|
|
|
|
|
return readdir(dir);
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-14 15:19:14 -07:00
|
|
|
int32_t mz_os_close_dir(DIR *dir) {
|
2023-02-19 11:17:54 -08:00
|
|
|
if (!dir)
|
2017-10-05 23:32:57 -07:00
|
|
|
return MZ_PARAM_ERROR;
|
|
|
|
|
if (closedir(dir) == -1)
|
|
|
|
|
return MZ_INTERNAL_ERROR;
|
|
|
|
|
return MZ_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-06 01:32:36 +02:00
|
|
|
int32_t mz_os_is_dir_separator(char c) {
|
2025-04-14 00:00:07 +02:00
|
|
|
#if MZ_PRESERVE_NATIVE_STRUCTURE
|
|
|
|
|
// While not strictly adhering to 4.4.17.1,
|
|
|
|
|
// this preserves UNIX filesystem structure.
|
2024-11-24 19:09:36 +01:00
|
|
|
return c == '/';
|
2025-04-14 00:00:07 +02:00
|
|
|
#else
|
|
|
|
|
// While strictly adhering to 4.4.17.1,
|
|
|
|
|
// this corrupts UNIX filesystem structure (a filename with a '\\' will become a folder + a file).
|
|
|
|
|
return c == '\\' || c == '/';
|
|
|
|
|
#endif
|
2024-11-24 19:09:36 +01:00
|
|
|
}
|
|
|
|
|
|
2020-06-14 15:19:14 -07:00
|
|
|
int32_t mz_os_is_dir(const char *path) {
|
2017-10-05 23:32:57 -07:00
|
|
|
struct stat path_stat;
|
2018-11-24 17:08:11 -08:00
|
|
|
|
|
|
|
|
memset(&path_stat, 0, sizeof(path_stat));
|
2017-10-05 23:32:57 -07:00
|
|
|
stat(path, &path_stat);
|
2017-10-16 18:50:32 -07:00
|
|
|
if (S_ISDIR(path_stat.st_mode))
|
2017-10-05 23:32:57 -07:00
|
|
|
return MZ_OK;
|
2018-11-24 17:08:11 -08:00
|
|
|
|
2017-10-05 23:32:57 -07:00
|
|
|
return MZ_EXIST_ERROR;
|
2017-10-06 00:02:28 -07:00
|
|
|
}
|
2018-09-18 12:06:54 +02:00
|
|
|
|
2020-06-14 15:19:14 -07:00
|
|
|
int32_t mz_os_is_symlink(const char *path) {
|
2019-05-02 21:07:39 -07:00
|
|
|
struct stat path_stat;
|
|
|
|
|
|
|
|
|
|
memset(&path_stat, 0, sizeof(path_stat));
|
2019-05-05 20:13:58 -07:00
|
|
|
lstat(path, &path_stat);
|
2019-05-02 21:07:39 -07:00
|
|
|
if (S_ISLNK(path_stat.st_mode))
|
|
|
|
|
return MZ_OK;
|
|
|
|
|
|
|
|
|
|
return MZ_EXIST_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-26 18:21:36 -07:00
|
|
|
int32_t mz_os_get_link_attribs(const char *path, uint32_t *attributes) {
|
|
|
|
|
struct stat path_stat;
|
|
|
|
|
int32_t err = MZ_OK;
|
|
|
|
|
|
|
|
|
|
memset(&path_stat, 0, sizeof(path_stat));
|
|
|
|
|
if (lstat(path, &path_stat) == -1)
|
|
|
|
|
err = MZ_INTERNAL_ERROR;
|
|
|
|
|
*attributes = path_stat.st_mode;
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-14 15:19:14 -07:00
|
|
|
int32_t mz_os_make_symlink(const char *path, const char *target_path) {
|
2026-04-20 17:26:22 -07:00
|
|
|
#if !HAVE_SYMLINK
|
2025-11-17 13:54:11 +08:00
|
|
|
return MZ_SUPPORT_ERROR;
|
2026-04-09 02:41:00 +01:00
|
|
|
#else
|
2019-05-02 21:07:39 -07:00
|
|
|
if (symlink(target_path, path) != 0)
|
|
|
|
|
return MZ_INTERNAL_ERROR;
|
|
|
|
|
return MZ_OK;
|
2025-11-17 13:54:11 +08:00
|
|
|
#endif
|
2019-05-02 21:07:39 -07:00
|
|
|
}
|
|
|
|
|
|
2020-06-14 15:19:14 -07:00
|
|
|
int32_t mz_os_read_symlink(const char *path, char *target_path, int32_t max_target_path) {
|
2026-04-20 17:26:22 -07:00
|
|
|
#if !HAVE_READLINK
|
2025-11-17 13:54:11 +08:00
|
|
|
return MZ_SUPPORT_ERROR;
|
|
|
|
|
#else
|
2019-05-05 08:25:51 -07:00
|
|
|
size_t length = 0;
|
2019-05-02 21:07:39 -07:00
|
|
|
|
2019-05-05 09:28:49 -07:00
|
|
|
length = (size_t)readlink(path, target_path, max_target_path - 1);
|
|
|
|
|
if (length == (size_t)-1)
|
2019-05-02 21:07:39 -07:00
|
|
|
return MZ_EXIST_ERROR;
|
2026-01-27 09:27:44 -08:00
|
|
|
if (length >= (size_t)(max_target_path - 1))
|
|
|
|
|
return MZ_BUF_ERROR;
|
2019-05-02 21:07:39 -07:00
|
|
|
|
|
|
|
|
target_path[length] = 0;
|
|
|
|
|
return MZ_OK;
|
2025-11-17 13:54:11 +08:00
|
|
|
#endif
|
2019-05-02 21:07:39 -07:00
|
|
|
}
|
|
|
|
|
|
2026-01-21 13:46:57 -08:00
|
|
|
int32_t mz_os_get_temp_path(char *path, int32_t max_path, const char *prefix) {
|
|
|
|
|
const char *tmp_dir = NULL;
|
2026-04-09 02:41:00 +01:00
|
|
|
char *temp_path;
|
2026-01-21 13:46:57 -08:00
|
|
|
int32_t result = 0;
|
|
|
|
|
|
|
|
|
|
if (!path || max_path <= 0)
|
|
|
|
|
return MZ_PARAM_ERROR;
|
|
|
|
|
|
|
|
|
|
tmp_dir = getenv("TMPDIR");
|
|
|
|
|
if (!tmp_dir)
|
|
|
|
|
tmp_dir = getenv("TMP");
|
|
|
|
|
if (!tmp_dir)
|
|
|
|
|
tmp_dir = getenv("TEMP");
|
|
|
|
|
if (!tmp_dir)
|
|
|
|
|
tmp_dir = "/tmp";
|
|
|
|
|
|
2026-04-09 02:41:00 +01:00
|
|
|
/* Construct path for mkdtemp in the form <tmp_dir>/<prefix>XXXXXX */
|
|
|
|
|
temp_path = (char *)calloc(max_path, sizeof(char));
|
|
|
|
|
if (!temp_path)
|
|
|
|
|
return MZ_MEM_ERROR;
|
|
|
|
|
|
|
|
|
|
/* mkdtemp replaces XXXXXX with unique characters */
|
|
|
|
|
result = snprintf(temp_path, max_path, "%s/%sXXXXXX", tmp_dir, prefix ? prefix : "");
|
|
|
|
|
if (result < 0 || result >= max_path) {
|
|
|
|
|
free(temp_path);
|
2026-01-21 13:46:57 -08:00
|
|
|
return MZ_BUF_ERROR;
|
2026-04-09 02:41:00 +01:00
|
|
|
}
|
2026-01-21 13:46:57 -08:00
|
|
|
|
2026-04-09 02:41:00 +01:00
|
|
|
/* Create a temporary directory. */
|
|
|
|
|
if (!mkdtemp(temp_path)) {
|
|
|
|
|
free(temp_path);
|
2026-01-21 13:46:57 -08:00
|
|
|
return MZ_INTERNAL_ERROR;
|
2026-04-09 02:41:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Create a filename inside the temporary directory using current time */
|
2026-07-12 20:44:43 -04:00
|
|
|
result = snprintf(path, max_path, "%s/%" PRIdMAX "x", temp_path, (intmax_t)time(NULL));
|
2026-04-09 02:41:00 +01:00
|
|
|
if (result < 0 || result >= max_path) {
|
|
|
|
|
rmdir(temp_path);
|
|
|
|
|
free(temp_path);
|
|
|
|
|
return MZ_BUF_ERROR;
|
|
|
|
|
}
|
2026-01-21 13:46:57 -08:00
|
|
|
|
2026-04-09 02:41:00 +01:00
|
|
|
free(temp_path);
|
2026-01-21 13:46:57 -08:00
|
|
|
return MZ_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-14 15:19:14 -07:00
|
|
|
uint64_t mz_os_ms_time(void) {
|
2018-09-18 12:06:54 +02:00
|
|
|
struct timespec ts;
|
|
|
|
|
|
2018-10-25 21:31:23 -07:00
|
|
|
#if defined(__APPLE__)
|
2018-09-18 12:06:54 +02:00
|
|
|
clock_serv_t cclock;
|
|
|
|
|
mach_timespec_t mts;
|
2018-09-18 20:25:48 -07:00
|
|
|
|
2018-09-18 12:06:54 +02:00
|
|
|
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
|
|
|
|
|
clock_get_time(cclock, &mts);
|
|
|
|
|
mach_port_deallocate(mach_task_self(), cclock);
|
2018-09-18 20:25:48 -07:00
|
|
|
|
2018-09-18 12:06:54 +02:00
|
|
|
ts.tv_sec = mts.tv_sec;
|
|
|
|
|
ts.tv_nsec = mts.tv_nsec;
|
2023-03-24 19:00:29 +00:00
|
|
|
#elif !defined(_POSIX_MONOTONIC_CLOCK) || _POSIX_MONOTONIC_CLOCK < 0
|
|
|
|
|
clock_gettime(CLOCK_REALTIME, &ts);
|
|
|
|
|
#elif _POSIX_MONOTONIC_CLOCK > 0
|
2018-09-18 12:06:54 +02:00
|
|
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
2023-03-24 19:00:29 +00:00
|
|
|
#else
|
|
|
|
|
if (sysconf(_SC_MONOTONIC_CLOCK) > 0)
|
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
|
|
|
else
|
|
|
|
|
clock_gettime(CLOCK_REALTIME, &ts);
|
2018-09-18 12:06:54 +02:00
|
|
|
#endif
|
|
|
|
|
|
2018-10-08 22:41:16 -07:00
|
|
|
return ((uint64_t)ts.tv_sec * 1000) + ((uint64_t)ts.tv_nsec / 1000000);
|
2018-09-18 12:06:54 +02:00
|
|
|
}
|