1 /* mz_os_posix.c -- System functions for posix
2    Version 2.8.1, December 1, 2018
3    part of the MiniZip project
4 
5    Copyright (C) 2010-2018 Nathan Moinvaziri
6      https://github.com/nmoinvaz/minizip
7 
8    This program is distributed under the terms of the same license as zlib.
9    See the accompanying LICENSE file for the full text of the license.
10 */
11 
12 #include "mz.h"
13 #include "mz_strm.h"
14 #include "mz_os.h"
15 
16 #include <stdio.h> /* rename */
17 #include <errno.h>
18 #include <iconv.h>
19 
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 
23 #if defined(__APPLE__) || defined(__unix__)
24 #  include <utime.h>
25 #  include <unistd.h>
26 #endif
27 #if defined(__APPLE__)
28 #  include <mach/clock.h>
29 #  include <mach/mach.h>
30 #endif
31 
32 /***************************************************************************/
33 
mz_os_utf8_string_create(const char * string,int32_t encoding)34 uint8_t *mz_os_utf8_string_create(const char *string, int32_t encoding)
35 {
36     iconv_t cd;
37     const char *from_encoding = NULL;
38     int32_t result = 0;
39     size_t string_length = 0;
40     size_t string_utf8_size = 0;
41     uint8_t *string_utf8 = NULL;
42     uint8_t *string_utf8_ptr = NULL;
43 
44     if (string == NULL)
45         return NULL;
46 
47     if (encoding == MZ_ENCODING_CODEPAGE_437)
48         from_encoding = "CP437";
49     else if (encoding == MZ_ENCODING_CODEPAGE_932)
50         from_encoding = "CP932";
51     else if (encoding == MZ_ENCODING_CODEPAGE_936)
52         from_encoding = "CP936";
53     else if (encoding == MZ_ENCODING_CODEPAGE_950)
54         from_encoding = "CP950";
55     else if (encoding == MZ_ENCODING_UTF8)
56         from_encoding = "UTF-8";
57     else
58         return NULL;
59 
60     cd = iconv_open("UTF-8", from_encoding);
61     if (cd == (iconv_t)-1)
62         return NULL;
63 
64     string_length = strlen(string);
65     string_utf8_size = string_length * 2;
66     string_utf8 = (uint8_t *)MZ_ALLOC((int32_t)(string_utf8_size + 1));
67     string_utf8_ptr = string_utf8;
68 
69     if (string_utf8)
70     {
71         memset(string_utf8, 0, string_utf8_size + 1);
72 
73         result = iconv(cd, (char **)&string, &string_length,
74                 (char **)&string_utf8_ptr, &string_utf8_size);
75 
76         iconv_close(cd);
77     }
78 
79     if (result == -1)
80     {
81         MZ_FREE(string_utf8);
82         string_utf8 = NULL;
83     }
84 
85     return string_utf8;
86 }
87 
mz_os_utf8_string_delete(uint8_t ** string)88 void mz_os_utf8_string_delete(uint8_t **string)
89 {
90     if (string != NULL)
91     {
92         MZ_FREE(*string);
93         *string = NULL;
94     }
95 }
96 
97 /***************************************************************************/
98 
mz_os_rand(uint8_t * buf,int32_t size)99 int32_t mz_os_rand(uint8_t *buf, int32_t size)
100 {
101     static unsigned calls = 0;
102     int32_t i = 0;
103 
104     /* Ensure different random header each time */
105     if (++calls == 1)
106     {
107         #define PI_SEED 3141592654UL
108         srand((unsigned)(time(NULL) ^ PI_SEED));
109     }
110 
111     while (i < size)
112         buf[i++] = (rand() >> 7) & 0xff;
113 
114     return size;
115 }
116 
mz_os_rename(const char * source_path,const char * target_path)117 int32_t mz_os_rename(const char *source_path, const char *target_path)
118 {
119     if (rename(source_path, target_path) == -1)
120         return MZ_EXIST_ERROR;
121 
122     return MZ_OK;
123 }
124 
mz_os_delete(const char * path)125 int32_t mz_os_delete(const char *path)
126 {
127     if (unlink(path) == -1)
128         return MZ_EXIST_ERROR;
129 
130     return MZ_OK;
131 }
132 
mz_os_file_exists(const char * path)133 int32_t mz_os_file_exists(const char *path)
134 {
135     struct stat path_stat;
136 
137     memset(&path_stat, 0, sizeof(path_stat));
138     if (stat(path, &path_stat) == 0)
139         return MZ_OK;
140     return MZ_EXIST_ERROR;
141 }
142 
mz_os_get_file_size(const char * path)143 int64_t mz_os_get_file_size(const char *path)
144 {
145     struct stat path_stat;
146 
147     memset(&path_stat, 0, sizeof(path_stat));
148     if (stat(path, &path_stat) == 0)
149     {
150         /* Stat returns size taken up by directory entry, so return 0 */
151         if (S_ISDIR(path_stat.st_mode))
152             return 0;
153 
154         return path_stat.st_size;
155     }
156 
157     return 0;
158 }
159 
mz_os_get_file_date(const char * path,time_t * modified_date,time_t * accessed_date,time_t * creation_date)160 int32_t mz_os_get_file_date(const char *path, time_t *modified_date, time_t *accessed_date, time_t *creation_date)
161 {
162     struct stat path_stat;
163     char *name = NULL;
164     size_t len = 0;
165     int32_t err = MZ_INTERNAL_ERROR;
166 
167     memset(&path_stat, 0, sizeof(path_stat));
168 
169     if (strcmp(path, "-") != 0)
170     {
171         /* Not all systems allow stat'ing a file with / appended */
172         len = strlen(path);
173         name = (char *)malloc(len + 1);
174         strncpy(name, path, len);
175         name[len] = 0;
176 
177         if (name[len - 1] == '/' || name[len - 1] == '\\')
178             name[len - 1] = 0;
179 
180         if (stat(name, &path_stat) == 0)
181         {
182             if (modified_date != NULL)
183                 *modified_date = path_stat.st_mtime;
184             if (accessed_date != NULL)
185                 *accessed_date = path_stat.st_atime;
186             /* Creation date not supported */
187             if (creation_date != NULL)
188                 *creation_date = 0;
189 
190             err = MZ_OK;
191         }
192 
193         free(name);
194     }
195 
196     return err;
197 }
198 
mz_os_set_file_date(const char * path,time_t modified_date,time_t accessed_date,time_t creation_date)199 int32_t mz_os_set_file_date(const char *path, time_t modified_date, time_t accessed_date, time_t creation_date)
200 {
201     struct utimbuf ut;
202 
203     ut.actime = accessed_date;
204     ut.modtime = modified_date;
205 
206     /* Creation date not supported */
207     MZ_UNUSED(creation_date);
208 
209     if (utime(path, &ut) != 0)
210         return MZ_INTERNAL_ERROR;
211 
212     return MZ_OK;
213 }
214 
mz_os_get_file_attribs(const char * path,uint32_t * attributes)215 int32_t mz_os_get_file_attribs(const char *path, uint32_t *attributes)
216 {
217     struct stat path_stat;
218     int32_t err = MZ_OK;
219 
220     memset(&path_stat, 0, sizeof(path_stat));
221     if (stat(path, &path_stat) == -1)
222         err = MZ_INTERNAL_ERROR;
223     *attributes = path_stat.st_mode;
224     return err;
225 }
226 
mz_os_set_file_attribs(const char * path,uint32_t attributes)227 int32_t mz_os_set_file_attribs(const char *path, uint32_t attributes)
228 {
229     int32_t err = MZ_OK;
230 
231     if (chmod(path, (mode_t)attributes) == -1)
232         err = MZ_INTERNAL_ERROR;
233 
234     return err;
235 }
236 
mz_os_make_dir(const char * path)237 int32_t mz_os_make_dir(const char *path)
238 {
239     int32_t err = 0;
240 
241     err = mkdir(path, 0755);
242 
243     if (err != 0 && errno != EEXIST)
244         return MZ_INTERNAL_ERROR;
245 
246     return MZ_OK;
247 }
248 
mz_os_open_dir(const char * path)249 DIR* mz_os_open_dir(const char *path)
250 {
251     return opendir(path);
252 }
253 
mz_os_read_dir(DIR * dir)254 struct dirent* mz_os_read_dir(DIR *dir)
255 {
256     if (dir == NULL)
257         return NULL;
258     return readdir(dir);
259 }
260 
mz_os_close_dir(DIR * dir)261 int32_t mz_os_close_dir(DIR *dir)
262 {
263     if (dir == NULL)
264         return MZ_PARAM_ERROR;
265     if (closedir(dir) == -1)
266         return MZ_INTERNAL_ERROR;
267     return MZ_OK;
268 }
269 
mz_os_is_dir(const char * path)270 int32_t mz_os_is_dir(const char *path)
271 {
272     struct stat path_stat;
273 
274     memset(&path_stat, 0, sizeof(path_stat));
275     stat(path, &path_stat);
276     if (S_ISDIR(path_stat.st_mode))
277         return MZ_OK;
278 
279     return MZ_EXIST_ERROR;
280 }
281 
mz_os_ms_time(void)282 uint64_t mz_os_ms_time(void)
283 {
284     struct timespec ts;
285 
286 #if defined(__APPLE__)
287     clock_serv_t cclock;
288     mach_timespec_t mts;
289 
290     host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
291     clock_get_time(cclock, &mts);
292     mach_port_deallocate(mach_task_self(), cclock);
293 
294     ts.tv_sec = mts.tv_sec;
295     ts.tv_nsec = mts.tv_nsec;
296 #else
297     clock_gettime(CLOCK_MONOTONIC, &ts);
298 #endif
299 
300     return ((uint64_t)ts.tv_sec * 1000) + ((uint64_t)ts.tv_nsec / 1000000);
301 }
302