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